Introduction
Goal: to compare the difference in transcription factor enrichment
between sensitive and resistant cell lines across three different tumor
lines.
RNA-seq was run for three isogenic tumor cell lines (ex: OVCAR3,
OVCAR3A, OVCAR3B) across several isolines Sample preparation was
performed in Dr. Lang’s lab. Preparation of cells and RNA extraction was
done by Kendra, Josie, and Sydney. RNA seq library prep was done by
Kristen.
This notebook is based on this
training and a discussion with Avtar.
Biological Questions:
- How does transcription factor enrichment differ between these
cellines?
- How does transcription factor enrichment differ between the
sensitive and resistant cell lines?
- How does transcription factor enrichment differ between the
sensitive and resistant cell lines across isogenic lines
Gather and organize raw data
Setup metadata tables.
metadata.all <- as.data.frame(read.table("../deseq/metadata.csv", sep = ",", header = TRUE))
rownames(metadata.all) <- metadata.all$ShortName
# TODO: This should be incorporated into the metadata file. Just doing this out of laziness
for (row in 1:nrow(metadata.all)) {
isogenicRank <- 1
resistant <- 0
if (metadata.all$CellLine[row] %in% list("OVCAR3A", "OVCAR4A", "PEA2", "PEO4")) {
isogenicRank <- 2
resistant <- 1
} else if (metadata.all$CellLine[row] %in% list("OVCAR3B", "OVCAR4B", "PEO6")) {
isogenicRank <- 3
resistant <- 1
}
metadata.all$IsogenicRank[row] <- isogenicRank
metadata.all$Resistant[row] <- resistant
}
metadata.all$CellLine <- as.factor(metadata.all$CellLine)
metadata.all$IsogenicRank <- as.factor(metadata.all$IsogenicRank)
metadata.all$Resistant <- as.factor(metadata.all$Resistant)
metadata.all
sensitive_resistant_pairs <- c("OVCAR3A_vs_OVCAR3", "OVCAR3B_vs_OVCAR3", "OVCAR4A_vs_OVCAR4", "OVCAR4B_vs_OVCAR4", "PEA2_vs_PEA1", "PEO6_vs_PEO1", "PEO4_vs_PEO1")
Load Count matrix
countmatrix <- as.matrix(read.table("../../star_salmon/salmon.merged.gene_counts.tsv", sep = "\t", header = TRUE))
row.names(countmatrix) <- countmatrix[, "gene_name"]
countmatrix <- countmatrix[, 3:ncol(countmatrix)]
countmatrix.all <- matrix(as.numeric(countmatrix), ncol = ncol(countmatrix), dimnames = list(rownames(countmatrix), colnames(countmatrix)))
countmatrix.all <- round(countmatrix.all)
countmatrix.all <- countmatrix.all[, metadata.all$LongName]
colnames(countmatrix.all) <- metadata.all$ShortName[match(colnames(countmatrix.all), metadata.all$LongName)] # Renames the Salmon countmatrix using formatted short name
Creates a separate generated notebook file for each
sensitive-resistant pair.
for (pair in sensitive_resistant_pairs) {
split <- strsplit(pair, "_vs_")
cont <- split[[1]][2]
exp <- split[[1]][1]
# Creates another notebook that shares the same environment
outFile <- str_interp("generated-notebooks/magic-analysis-${pair}.html")
print(str_interp("Creating notebook for ${exp} vs ${cont}"))
rmarkdown::render('single-sensitive-resistant-pair-magic-analysis.Rmd',
output_file = outFile,
params = list(controlCellLine = cont,
experimentalCellLine = exp,
countmatrix.all = countmatrix.all,
metadata.all = metadata.all))
}
Analyze all samples together
Create a cls file with cell line categorization information
possible_categories <- unique(metadata.all$CellLine)
assigned_categories <- metadata.all$CellLine
num_categories <- length(possible_categories)
num_samples <- length(assigned_categories)
fileConn<-file("data/all_celllines.cls")
writeLines(
c(
str_interp("${num_samples}\t${num_categories}\t1"),
str_interp("#\t${paste(possible_categories, collapse='\t')}"),
str_interp("${paste(assigned_categories, collapse='\t')}")),
fileConn)
close(fileConn)
Filter out low-read genes to create our background gene set
Only retain genes for which there is a cell line that had at least 1
read for the gene in all of its replicates
str_interp("${nrow(countmatrix.all)} genes before filtration.")
[1] "29744 genes before filtration."
countmatrix.all.df <- as.data.frame(countmatrix.all)
for(row in 1:nrow(countmatrix.all.df)) {
keepGene <- FALSE
# for at least one of the cell lines
for (cellline in unique(metadata.all$CellLine)) {
allRead <- TRUE
# all of the replicates must have at least one read
for(i in 1:3) {
sampleName <- str_interp("${cellline}_R${i}")
if (countmatrix.all.df[row, sampleName] < 1) {
allRead <- FALSE
}
}
if (allRead) {
keepGene <- TRUE
}
}
if (keepGene) {
countmatrix.all.df$SufficientReads[row] <- TRUE
} else {
countmatrix.all.df$SufficientReads[row] <- FALSE
}
}
countmatrix.all.filtered <- countmatrix.all.df %>%
filter(SufficientReads)
str_interp("${nrow(countmatrix.all.filtered)} genes after filtration.")
[1] "20570 genes after filtration."
backgroundGenes.all <- rownames(countmatrix.all.filtered)
Differential expression analysis
Run Deseq on the data set.
# Having the replicate number in the design makes it a paired design
dds.all <- DESeqDataSetFromMatrix(
countData = countmatrix.all,
colData = metadata.all,
# design = ~ CellLine + Replicate + Resistant)
design = ~ CellLine + Replicate)
converting counts to integer mode
Warning: 61 duplicate rownames were renamed by adding numbers the design formula contains one or more numeric variables with integer values,
specifying a model with increasing fold change for higher values.
did you mean for this to be a factor? if so, first convert
this variable to a factor using the factor() function
Using a Likelihood Ratio Test rather than the Wald test allows us to
analyze all cellLines at once (rather than analyzing them pair-wise).
P-values are determined only by the difference in performance of the
full and reduced models. This answers whether the cell line explains a
significant amount of variation in the gene expression. We can then
examine all cell lines together.
# Full model includes Replicate + CellLine; Reduced model only includes Replicate
dds.all <- DESeq(dds.all, test="LRT",
reduced = ~ Replicate)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
# reduced = ~ CellLine + Replicate)
Filter and normalize deseq output
Filter out the low read genes that are not included in our background
gene list.
# Filter (recalculates p-adjusted values automatically)
dds.all.filtered <- subset(dds.all, rownames(dds.all) %in% backgroundGenes.all)
# Pull out results
res.all.lrt.filtered <- results(dds.all.filtered)
res.all.lrt.filtered <- as.data.frame(res.all.lrt.filtered[order(res.all.lrt.filtered$padj, decreasing = FALSE),])
as.data.frame(res.all.lrt.filtered)
# Pull out only significant results
sig.res.all.lrt.filtered <- res.all.lrt.filtered %>% filter(padj < 0.05)
sig.res.all.lrt.filtered
# Subset the dds for significant results
sigGenes.all <- rownames(sig.res.all.lrt.filtered)
dds.all.filtered.sig <- subset(dds.all.filtered, rownames(dds.all.filtered) %in% sigGenes.all)
Normalize the data using the median of ratios method and vst methods.
Chosen based on this
training
# Normalize using the median of ratios method, which incorporates sequencing depth and compositional bias
normalized_counts.all.filtered <- counts(dds.all.filtered, normalized=TRUE)
normalized_counts.all.lrt.filtered.sig <- counts(dds.all.filtered.sig, normalized=TRUE)
as.data.frame(counts(dds.all.filtered)) # non-normalized
as.data.frame(normalized_counts.all.filtered) # normalized
write.table(
as.data.frame(normalized_counts.all.filtered),
file="data/all_filtered_normalized_counts.txt",
sep="\t",
quote=F,
col.names=NA)
write.table(
as.data.frame(normalized_counts.all.lrt.filtered.sig),
file="data/all_filtered_sig_normalized_counts.txt",
sep="\t",
quote=F,
col.names=NA)
# Normalize using vst, which results in similar variance across samples. This is needed for PCA analysis
vst.dds.all.filtered <- vst(dds.all.filtered)
vst.dds.all.filtered.sig <- vst(dds.all.filtered.sig) # TODO: Should I take vst of significant peaks or subset the significant peaks from the vst of full data?
PCA Plots
All background genes. This plots the vst of the counts.
pcaData <- plotPCA(vst.dds.all.filtered, intgroup = c("CellLine", "ShortName"), returnData = TRUE)
percentVar <- round(100 * attr(pcaData, "percentVar"))
ggplot(pcaData, aes(PC1, PC2, color = CellLine, label = ShortName)) +
geom_point(size = 3) +
geom_text(hjust = 0, vjust = 0) +
xlab(paste0("PC1: ", percentVar[1], "% variance")) +
ylab(paste0("PC2: ", percentVar[2], "% variance")) +
coord_fixed()

Only significant genes. This plots the vst of the counts.
pcaData <- plotPCA(vst.dds.all.filtered.sig, intgroup = c("CellLine", "ShortName"), returnData = TRUE)
percentVar <- round(100 * attr(pcaData, "percentVar"))
ggplot(pcaData, aes(PC1, PC2, color = CellLine, label = ShortName)) +
geom_point(size = 3) +
geom_text(hjust = 0, vjust = 0) +
xlab(paste0("PC1: ", percentVar[1], "% variance")) +
ylab(paste0("PC2: ", percentVar[2], "% variance")) +
coord_fixed()

Cluster using Leiden clustering (script courtesy of Avtar)
python scripts/Leiden_cluster_genes.py Provide the files
data/all_filtered_sig_normalized_counts.txt and
data/all_celllines.cls When prompted, select “yes” for
centering the data and using means of conditions. Select “no” for taking
a subset of the significant genes (we have already performed this
subset). Default resolution is fine.
Copy output into gene_clusters folder:
cp data/all_filtered_sig_normalized_counts_clusters/clusters_centered.pdf gene_clusters/all_gene_clusters_centered.pdf
cp data/all_filtered_sig_normalized_counts_clusters/gene_cluster_lists.TSV gene_clusters/all_gene_cluster_s_centered.pdf_lists.TSV
This was for all isolines as well as the full data set. We will be
examining the isogenic lines individually using Magic. We used a
resolution of 0.1 to maximize coherent clustering
Analyze clusters across sensitive-resistant pairs
Run Magic
Use the run_magic.sh script.
Combining magic output
“The Score combines the corrected p value from this test and a
measure of how skewed the chip signals are towards high values in the
query versus background lists”
Combine per sensitive-resistant pair
all_sig_up_across_pairs_tfs <- c()
all_sig_down_across_pairs_tfs <- c()
# Read in magic output for each pair
for (pair in sensitive_resistant_pairs) {
for (dir in c("up", "down")) {
pair_tfs <- as.data.frame(
read_excel(
str_interp("magic_output/${pair}_output/${dir}_in_resistant/${dir}_in_resistant_summary.xlsx")))
pair_tfs <- pair_tfs[pair_tfs$padj < 0.5,] # If padj > 0.5 then this isn't really up
pair_tfs_sig <- pair_tfs[pair_tfs$padj < 0.05,]
assign(str_interp("${pair}_${dir}_tfs"), pair_tfs, pos = 1)
assign(str_interp("${pair}_${dir}_tfs_sig"), pair_tfs_sig, pos = 1)
if (dir == "up") {
all_sig_up_across_pairs_tfs <- list.append(all_sig_up_across_pairs_tfs, pair_tfs_sig$TF)
} else if (dir == "down") {
all_sig_down_across_pairs_tfs <- list.append(all_sig_down_across_pairs_tfs, pair_tfs_sig$TF)
} else {
print(str_interp("ISSUE! dir not valid: ${dir}"))
}
}
}
# All tfs that are significant in at least one isoline
combined_magic_output_sig_down <- data.frame(TF = unique(all_sig_down_across_pairs_tfs))
combined_magic_output_sig_up <- data.frame(TF = unique(all_sig_up_across_pairs_tfs))
for (pair in sensitive_resistant_pairs) {
pair_up_tfs <- get(str_interp("${pair}_up_tfs"))
pair_addition_up <- data.frame(pair_up_tfs$TF,
pair_up_tfs$Score,
pair_up_tfs$padj)
colnames(pair_addition_up) <- c("TF",
str_interp("${pair}_up_score"),
str_interp("${pair}_up_padj"))
pair_down_tfs <- get(str_interp("${pair}_down_tfs"))
pair_addition_down <- data.frame(pair_down_tfs$TF,
pair_down_tfs$Score,
pair_down_tfs$padj)
colnames(pair_addition_down) <- c("TF",
str_interp("${pair}_down_score"),
str_interp("${pair}_down_padj"))
# Add the info for up and down across all pairs regardless of significance
if (nrow(pair_addition_up) > 0) {
combined_magic_output_sig_up <- left_join(combined_magic_output_sig_up,
pair_addition_up,
by = "TF")
combined_magic_output_sig_down <- left_join(combined_magic_output_sig_down,
pair_addition_up,
by = "TF")
}
if (nrow(pair_addition_down) > 0) {
combined_magic_output_sig_up <- left_join(combined_magic_output_sig_up,
pair_addition_down,
by = "TF")
combined_magic_output_sig_down <- left_join(combined_magic_output_sig_down,
pair_addition_down,
by = "TF")
}
}
# Count the number of isolines that were significantly up/down in each TF
for (row in 1:nrow(combined_magic_output_sig_up)) {
num_sig_up <- 0
for (pair in sensitive_resistant_pairs) {
col_name <- paste0(pair, "_up_padj")
padj <- combined_magic_output_sig_up[row, col_name]
if (!is.na(padj) & padj < 0.05) {
num_sig_up <- num_sig_up + 1
}
}
num_sig_down <- 0
for (pair in sensitive_resistant_pairs) {
col_name <- paste0(pair, "_down_padj")
padj <- combined_magic_output_sig_up[row, col_name]
if (!is.na(padj) & padj < 0.05) {
num_sig_down <- num_sig_down + 1
}
}
combined_magic_output_sig_up[row, "num_pairs_sig_up"] <- num_sig_up
combined_magic_output_sig_up[row, "num_pairs_sig_down"] <- num_sig_down
}
# Count the number of isolines that were significantly up/down in each TF
for (row in 1:nrow(combined_magic_output_sig_down)) {
num_sig_up <- 0
for (pair in sensitive_resistant_pairs) {
col_name <- paste0(pair, "_up_padj")
padj <- combined_magic_output_sig_down[row, col_name]
if (!is.na(padj) & padj < 0.05) {
num_sig_up <- num_sig_up + 1
}
}
num_sig_down <- 0
for (pair in sensitive_resistant_pairs) {
col_name <- paste0(pair, "_down_padj")
padj <- combined_magic_output_sig_down[row, col_name]
if (!is.na(padj) & padj < 0.05) {
num_sig_down <- num_sig_down + 1
}
}
combined_magic_output_sig_down[row, "num_pairs_sig_up"] <- num_sig_up
combined_magic_output_sig_down[row, "num_pairs_sig_down"] <- num_sig_down
}
# Reorder columns
col_names <- c("TF", "num_pairs_sig_up", "num_pairs_sig_down")
for (dir in c("up", "down")) {
for (pair in sensitive_resistant_pairs) {
col_name <- paste0(pair, "_", dir, "_score")
col_names <- append(col_names, col_name)
col_name <- paste0(pair, "_", dir, "_padj")
col_names <- append(col_names, col_name)
}
}
rownames(combined_magic_output_sig_up) <- combined_magic_output_sig_up$TF
combined_magic_output_sig_up <- combined_magic_output_sig_up[, col_names]
rownames(combined_magic_output_sig_down) <- combined_magic_output_sig_down$TF
combined_magic_output_sig_down <- combined_magic_output_sig_down[, col_names]
# Sort by num significant
combined_magic_output_sig_up <- combined_magic_output_sig_up[order(combined_magic_output_sig_up$num_pairs_sig_up, decreasing=TRUE),]
combined_magic_output_sig_down <- combined_magic_output_sig_down[order(combined_magic_output_sig_down$num_pairs_sig_down, decreasing=TRUE),]
# Tables include TF info across all isolines for each tf that is up/down regulated significantly in at least one isoline
print(combined_magic_output_sig_up)
print(combined_magic_output_sig_down)
write.table(combined_magic_output_sig_up,
file = str_interp("differential_tfs/combined_magic_output_up_sig_sensitive-resistant-pairs.txt"),
quote = FALSE,
row.names = FALSE,
na = "",
sep = "\t")
write.table(combined_magic_output_sig_down,
file = str_interp("differential_tfs/combined_magic_output_down_sig_sensitive-resistant-pairs.txt"),
quote = FALSE,
row.names = FALSE,
na = "",
sep = "\t")
Only consider unidirectional results.
for (pair in sensitive_resistant_pairs) {
pair_up_tfs_sig <- get(str_interp("${pair}_up_tfs_sig"))
pair_down_tfs_sig <- get(str_interp("${pair}_down_tfs_sig"))
# Subset unidirectional results
pair_sig_up_only_tfs <- pair_up_tfs_sig[!(pair_up_tfs_sig$TF %in% pair_down_tfs_sig$TF), ]
pair_sig_down_only_tfs <- pair_down_tfs_sig[!(pair_down_tfs_sig$TF %in% pair_up_tfs_sig$TF), ]
# Save R data
assign(str_interp("${pair}_sig_up_only_tfs"), pair_sig_up_only_tfs)
assign(str_interp("${pair}_sig_down_only_tfs"), pair_sig_down_only_tfs)
# Write to file
write.table(pair_sig_up_only_tfs,
str_interp("differential_tfs/${pair}_tfs_only_sig_up.txt"),
quote = FALSE,
row.names = FALSE,
col.names = TRUE,
sep = "\t")
write.table(pair_sig_down_only_tfs,
str_interp("differential_tfs/${pair}_tfs_only_sig_down.txt"),
quote = FALSE,
row.names = FALSE,
col.names = TRUE,
sep = "\t")
}
Create an upset plot of the TFs that were significant in either up or
down expressed genes (but not both) within a given sensitive/resistant
pair.
tf_list_names <- c()
upset_list_input <- c()
for (dir in c("up", "down")) {
for (pair in sensitive_resistant_pairs) {
name <- str_interp("${pair}_${dir}_only_tfs")
list <- get(str_interp("${pair}_sig_${dir}_only_tfs"))
tf_list_names <- append(tf_list_names, name)
upset_list_input[[length(upset_list_input)+1]] <- list$TF # notation necessary to add to list of lists
}
}
names(upset_list_input) <- tf_list_names
upset_groups <- getUpsetPlotData(upset_list_input)
print(upset_groups)
write.table(upset_groups,
"differential_tfs/unidirectional_differential_tfs_by_sensitive-resistant-pairs_upset_plot.txt",
quote = FALSE,
row.names = FALSE,
col.names = TRUE,
na = "",
sep = "\t")
upset(fromList(upset_list_input), nsets = 7, nintersects = 50, order.by = "degree", keep.order = TRUE, sets = tf_list_names)


LS0tCnRpdGxlOiAiU2Vjb25kYXJ5IGFuYWx5c2lzIG9mIDIzMDMyNC0zd2F5LW1lcmdlIFJOQS1zZXEgc2Vuc2l0aXZlIHZzIHJlc2lzdGFudCBjZWxsIGxpbmVzIGFjcm9zcyBzZXZlcmFsIGlzb2xpbmVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCiAgCiMjIEludHJvZHVjdGlvbiAgCgpHb2FsOiB0byBjb21wYXJlIHRoZSBkaWZmZXJlbmNlIGluIHRyYW5zY3JpcHRpb24gZmFjdG9yIGVucmljaG1lbnQgYmV0d2VlbiBzZW5zaXRpdmUgYW5kIHJlc2lzdGFudCBjZWxsIGxpbmVzIGFjcm9zcyB0aHJlZSBkaWZmZXJlbnQgdHVtb3IgbGluZXMuCgpSTkEtc2VxIHdhcyBydW4gZm9yIHRocmVlIGlzb2dlbmljIHR1bW9yIGNlbGwgbGluZXMgKGV4OiBPVkNBUjMsIE9WQ0FSM0EsIE9WQ0FSM0IpIGFjcm9zcyBzZXZlcmFsIGlzb2xpbmVzClNhbXBsZSBwcmVwYXJhdGlvbiB3YXMgcGVyZm9ybWVkIGluIERyLiBMYW5nJ3MgbGFiLiBQcmVwYXJhdGlvbiBvZiBjZWxscyBhbmQgUk5BIGV4dHJhY3Rpb24gd2FzIGRvbmUgYnkgS2VuZHJhLCBKb3NpZSwgYW5kIFN5ZG5leS4KUk5BIHNlcSBsaWJyYXJ5IHByZXAgd2FzIGRvbmUgYnkgS3Jpc3Rlbi4KClRoaXMgbm90ZWJvb2sgaXMgYmFzZWQgb24gW3RoaXMgdHJhaW5pbmddKGh0dHBzOi8vaGJjdHJhaW5pbmcuZ2l0aHViLmlvL0RHRV93b3Jrc2hvcC9sZXNzb25zLzA4X0RHRV9MUlQuaHRtbCkgYW5kIGEgZGlzY3Vzc2lvbiB3aXRoIEF2dGFyLgoKQmlvbG9naWNhbCBRdWVzdGlvbnM6CgogKiBIb3cgZG9lcyB0cmFuc2NyaXB0aW9uIGZhY3RvciBlbnJpY2htZW50IGRpZmZlciBiZXR3ZWVuIHRoZXNlIGNlbGxpbmVzPwogKiBIb3cgZG9lcyB0cmFuc2NyaXB0aW9uIGZhY3RvciBlbnJpY2htZW50IGRpZmZlciBiZXR3ZWVuIHRoZSBzZW5zaXRpdmUgYW5kIHJlc2lzdGFudCBjZWxsIGxpbmVzPwogKiBIb3cgZG9lcyB0cmFuc2NyaXB0aW9uIGZhY3RvciBlbnJpY2htZW50IGRpZmZlciBiZXR3ZWVuIHRoZSBzZW5zaXRpdmUgYW5kIHJlc2lzdGFudCBjZWxsIGxpbmVzIGFjcm9zcyBpc29nZW5pYyBsaW5lcwoKIyMgSW5wdXRzCgpgYGB7ciBsb2FkIHBhY2thZ2VzLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoREVTZXEyKQpsaWJyYXJ5KHZzbikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShiaW9tYVJ0KQpsaWJyYXJ5KERFU2VxQW5hbHlzaXMpCmxpYnJhcnkoREVHcmVwb3J0KQpsaWJyYXJ5KFVwU2V0UikKbGlicmFyeShncHJvZmlsZXIyKQpsaWJyYXJ5KHJydmdvKQpsaWJyYXJ5KEdPLmRiKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShybGlzdCkKR08gPC0gYXMubGlzdChHT1RFUk0pCmBgYAoKRGVmaW5lIHVwc2V0IHBsb3QgaGVscGVyIGZ1bmN0aW9ucyAoY29kZSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9obXMtZGJtaS9VcFNldFIvaXNzdWVzLzg1I2lzc3VlY29tbWVudC00MTU0ODA5NTQpCmBgYHtyIGluY2x1ZGU9RkFMU0V9Cm92ZXJsYXBHcm91cHMgPC0gZnVuY3Rpb24gKGxpc3RJbnB1dCwgc29ydCA9IFRSVUUpIHsKICAjIGxpc3RJbnB1dCBjb3VsZCBsb29rIGxpa2UgdGhpczoKICAjICRvbmUKICAjIFsxXSAiYSIgImIiICJjIiAiZSIgImciICJoIiAiayIgImwiICJtIgogICMgJHR3bwogICMgWzFdICJhIiAiYiIgImQiICJlIiAiaiIKICAjICR0aHJlZQogICMgWzFdICJhIiAiZSIgImYiICJnIiAiaCIgImkiICJqIiAibCIgIm0iCiAgbGlzdElucHV0bWF0ICAgIDwtIGZyb21MaXN0KGxpc3RJbnB1dCkgPT0gMQogICMgICAgIG9uZSAgIHR3byB0aHJlZQogICMgYSAgVFJVRSAgVFJVRSAgVFJVRQogICMgYiAgVFJVRSAgVFJVRSBGQUxTRQogICMuLi4KICAjIGNvbmRlbnNpbmcgbWF0cml4IHRvIHVuaXF1ZSBjb21iaW5hdGlvbnMgZWxlbWVudHMKICBsaXN0SW5wdXR1bmlxdWUgPC0gdW5pcXVlKGxpc3RJbnB1dG1hdCkKICBncm91cGxpc3QgPC0gbGlzdCgpCiAgIyBnb2luZyB0aHJvdWdoIGFsbCB1bmlxdWUgY29tYmluYXRpb25zIGFuZCBjb2xsZWN0IGVsZW1lbnRzIGZvciBlYWNoIGluIGEgbGlzdAogIGZvciAoaSBpbiAxOm5yb3cobGlzdElucHV0dW5pcXVlKSkgewogICAgY3VycmVudFJvdyA8LSBsaXN0SW5wdXR1bmlxdWVbaSxdCiAgICBteWVsZW1lbnRzIDwtIHdoaWNoKGFwcGx5KGxpc3RJbnB1dG1hdCwxLGZ1bmN0aW9uKHgpIGFsbCh4ID09IGN1cnJlbnRSb3cpKSkKICAgIGF0dHIobXllbGVtZW50cywgImdyb3VwcyIpIDwtIGN1cnJlbnRSb3cKICAgIGdyb3VwbGlzdFtbcGFzdGUoY29sbmFtZXMobGlzdElucHV0dW5pcXVlKVtjdXJyZW50Um93XSwgY29sbGFwc2UgPSAiOiIpXV0gPC0gbXllbGVtZW50cwogICAgbXllbGVtZW50cwogICAgIyBhdHRyKCwiZ3JvdXBzIikKICAgICMgICBvbmUgICB0d28gdGhyZWUgCiAgICAjIEZBTFNFIEZBTFNFICBUUlVFIAogICAgIyAgZiAgaSAKICAgICMgMTIgMTMgCiAgfQogIGlmIChzb3J0KSB7CiAgICBncm91cGxpc3QgPC0gZ3JvdXBsaXN0W29yZGVyKHNhcHBseShncm91cGxpc3QsIGZ1bmN0aW9uKHgpIGxlbmd0aCh4KSksIGRlY3JlYXNpbmcgPSBUUlVFKV0KICB9CiAgYXR0cihncm91cGxpc3QsICJlbGVtZW50cyIpIDwtIHVuaXF1ZSh1bmxpc3QobGlzdElucHV0KSkKICByZXR1cm4oZ3JvdXBsaXN0KQp9CgpnZXRVcHNldFBsb3REYXRhIDwtIGZ1bmN0aW9uKGxpc3RJbnB1dCkgewogICMgbGlzdElucHV0IGNvdWxkIGxvb2sgbGlrZSB0aGlzOgogICMgJG9uZQogICMgWzFdICJhIiAiYiIgImMiICJlIiAiZyIgImgiICJrIiAibCIgIm0iCiAgIyAkdHdvCiAgIyBbMV0gImEiICJiIiAiZCIgImUiICJqIgogICMgJHRocmVlCiAgIyBbMV0gImEiICJlIiAiZiIgImciICJoIiAiaSIgImoiICJsIiAibSIKICB1cHNldFBsb3REYXRhLm1lc3N5IDwtIG92ZXJsYXBHcm91cHMobGlzdElucHV0KQogIHVwc2V0UGxvdERhdGEgPC0gcHVycnI6Om1hcCh1cHNldFBsb3REYXRhLm1lc3N5LCB+IGF0dHIodXBzZXRQbG90RGF0YS5tZXNzeSwgImVsZW1lbnRzIilbLnhdKQogICMgQWRkcyBOQSB2YWx1ZXMgdW50aWwgZWFjaCBpcyB0aGUgc2FtZSBsZW5ndGggc28gd2UgY2FuIGZvcm1hdCBpbiBhIGRhdGEgZnJhbWUKICB1cHNldFBsb3REYXRhLmRmIDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KHVwc2V0UGxvdERhdGEsIGBsZW5ndGg8LWAsIG1heChsZW5ndGhzKHVwc2V0UGxvdERhdGEpKSkpCiAgcmV0dXJuKHVwc2V0UGxvdERhdGEuZGYpCn0KYGBgCgojIyBHYXRoZXIgYW5kIG9yZ2FuaXplIHJhdyBkYXRhCgpTZXR1cCBtZXRhZGF0YSB0YWJsZXMuCgpgYGB7ciBsb2FkIG1ldGF0YWJsZX0KbWV0YWRhdGEuYWxsIDwtIGFzLmRhdGEuZnJhbWUocmVhZC50YWJsZSgiLi4vZGVzZXEvbWV0YWRhdGEuY3N2Iiwgc2VwID0gIiwiLCBoZWFkZXIgPSBUUlVFKSkKcm93bmFtZXMobWV0YWRhdGEuYWxsKSA8LSBtZXRhZGF0YS5hbGwkU2hvcnROYW1lCiMgVE9ETzogVGhpcyBzaG91bGQgYmUgaW5jb3Jwb3JhdGVkIGludG8gdGhlIG1ldGFkYXRhIGZpbGUuIEp1c3QgZG9pbmcgdGhpcyBvdXQgb2YgbGF6aW5lc3MKZm9yIChyb3cgaW4gMTpucm93KG1ldGFkYXRhLmFsbCkpIHsKICAgIGlzb2dlbmljUmFuayA8LSAxCiAgICByZXNpc3RhbnQgPC0gMAogICAgaWYgKG1ldGFkYXRhLmFsbCRDZWxsTGluZVtyb3ddICVpbiUgbGlzdCgiT1ZDQVIzQSIsICJPVkNBUjRBIiwgIlBFQTIiLCAiUEVPNCIpKSB7CiAgICAgIGlzb2dlbmljUmFuayA8LSAyCiAgICAgIHJlc2lzdGFudCA8LSAxCiAgICB9IGVsc2UgaWYgKG1ldGFkYXRhLmFsbCRDZWxsTGluZVtyb3ddICVpbiUgbGlzdCgiT1ZDQVIzQiIsICJPVkNBUjRCIiwgIlBFTzYiKSkgewogICAgICBpc29nZW5pY1JhbmsgPC0gMwogICAgICByZXNpc3RhbnQgPC0gMQogICAgfQogICAgbWV0YWRhdGEuYWxsJElzb2dlbmljUmFua1tyb3ddIDwtIGlzb2dlbmljUmFuawogICAgbWV0YWRhdGEuYWxsJFJlc2lzdGFudFtyb3ddIDwtIHJlc2lzdGFudAp9Cm1ldGFkYXRhLmFsbCRDZWxsTGluZSA8LSBhcy5mYWN0b3IobWV0YWRhdGEuYWxsJENlbGxMaW5lKQptZXRhZGF0YS5hbGwkSXNvZ2VuaWNSYW5rIDwtIGFzLmZhY3RvcihtZXRhZGF0YS5hbGwkSXNvZ2VuaWNSYW5rKQptZXRhZGF0YS5hbGwkUmVzaXN0YW50IDwtIGFzLmZhY3RvcihtZXRhZGF0YS5hbGwkUmVzaXN0YW50KQptZXRhZGF0YS5hbGwKCnNlbnNpdGl2ZV9yZXNpc3RhbnRfcGFpcnMgPC0gYygiT1ZDQVIzQV92c19PVkNBUjMiLCAiT1ZDQVIzQl92c19PVkNBUjMiLCAiT1ZDQVI0QV92c19PVkNBUjQiLCAiT1ZDQVI0Ql92c19PVkNBUjQiLCAiUEVBMl92c19QRUExIiwgIlBFTzZfdnNfUEVPMSIsICJQRU80X3ZzX1BFTzEiKQpgYGAKCkxvYWQgQ291bnQgbWF0cml4CgpgYGB7ciByZWFkIGNvdW50IG1hdHJpeH0KY291bnRtYXRyaXggPC0gYXMubWF0cml4KHJlYWQudGFibGUoIi4uLy4uL3N0YXJfc2FsbW9uL3NhbG1vbi5tZXJnZWQuZ2VuZV9jb3VudHMudHN2Iiwgc2VwID0gIlx0IiwgaGVhZGVyID0gVFJVRSkpCnJvdy5uYW1lcyhjb3VudG1hdHJpeCkgPC0gY291bnRtYXRyaXhbLCAiZ2VuZV9uYW1lIl0KY291bnRtYXRyaXggPC0gY291bnRtYXRyaXhbLCAzOm5jb2woY291bnRtYXRyaXgpXQpjb3VudG1hdHJpeC5hbGwgPC0gbWF0cml4KGFzLm51bWVyaWMoY291bnRtYXRyaXgpLCBuY29sID0gbmNvbChjb3VudG1hdHJpeCksIGRpbW5hbWVzID0gbGlzdChyb3duYW1lcyhjb3VudG1hdHJpeCksIGNvbG5hbWVzKGNvdW50bWF0cml4KSkpCmNvdW50bWF0cml4LmFsbCA8LSByb3VuZChjb3VudG1hdHJpeC5hbGwpCmNvdW50bWF0cml4LmFsbCA8LSBjb3VudG1hdHJpeC5hbGxbLCBtZXRhZGF0YS5hbGwkTG9uZ05hbWVdCmNvbG5hbWVzKGNvdW50bWF0cml4LmFsbCkgPC0gbWV0YWRhdGEuYWxsJFNob3J0TmFtZVttYXRjaChjb2xuYW1lcyhjb3VudG1hdHJpeC5hbGwpLCBtZXRhZGF0YS5hbGwkTG9uZ05hbWUpXSAjIFJlbmFtZXMgdGhlIFNhbG1vbiBjb3VudG1hdHJpeCB1c2luZyBmb3JtYXR0ZWQgc2hvcnQgbmFtZQpgYGAKCjwhLS0gIyMgQ3JlYXRlcyBhIHNlcGFyYXRlIGdlbmVyYXRlZCBub3RlYm9vayBmaWxlIGZvciBlYWNoIGluZGl2aWR1YWwgaXNvbGluZS4gLS0+Cgo8IS0tIGBgYHtyIGluZGl2aWR1YWwgaXNvbGluZSBub3RlYm9va3MsIHJlc3VsdHMgPSBGQUxTRX0gLS0+CjwhLS0gZm9yIChpc29saW5lIGluIHVuaXF1ZShtZXRhZGF0YS5hbGwkSXNvTGluZSkpIHsgLS0+CjwhLS0gICBjb250IDwtIHVuaXF1ZShtZXRhZGF0YS5hbGxbbWV0YWRhdGEuYWxsJElzb0xpbmUgPT0gaXNvbGluZSAmIG1ldGFkYXRhLmFsbCRSZXNpc3RhbnQgPT0gMCwgIkNlbGxMaW5lIl0pIC0tPgo8IS0tICAgZXhwcyA8LSB1bmlxdWUobWV0YWRhdGEuYWxsW21ldGFkYXRhLmFsbCRJc29MaW5lID09IGlzb2xpbmUgJiBtZXRhZGF0YS5hbGwkUmVzaXN0YW50ID09IDEsICJDZWxsTGluZSJdKSAtLT4KPCEtLSAgICMgQ3JlYXRlcyBhbm90aGVyIG5vdGVib29rIHRoYXQgc2hhcmVzIHRoZSBzYW1lIGVudmlyb25tZW50IC0tPgo8IS0tICAgb3V0RmlsZSA8LSBzdHJfaW50ZXJwKCJnZW5lcmF0ZWQtbm90ZWJvb2tzL21hZ2ljLWFuYWx5c2lzLSR7aXNvbGluZX0uaHRtbCIpIC0tPgo8IS0tICAgcm1hcmtkb3duOjpyZW5kZXIoJ3NpbmdsZS1pc29saW5lLW1hZ2ljLWFuYWx5c2lzLlJtZCcsICAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgIG91dHB1dF9maWxlID0gb3V0RmlsZSwgIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgcGFyYW1zID0gbGlzdChpc29saW5lID0gaXNvbGluZSwgIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sQ2VsbExpbmUgPSBjb250LCAgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVyaW1lbnRhbENlbGxMaW5lcyA9IGV4cHMsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudG1hdHJpeC5hbGwgPSBjb3VudG1hdHJpeC5hbGwsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YS5hbGwgPSBtZXRhZGF0YS5hbGwpKSAtLT4KPCEtLSB9IC0tPgo8IS0tIGBgYCAtLT4KCiMjIENyZWF0ZXMgYSBzZXBhcmF0ZSBnZW5lcmF0ZWQgbm90ZWJvb2sgZmlsZSBmb3IgZWFjaCBzZW5zaXRpdmUtcmVzaXN0YW50IHBhaXIuCgpgYGB7ciBpbmRpdmlkdWFsIHBhaXIgbm90ZWJvb2tzLCByZXN1bHRzID0gRkFMU0V9CmZvciAocGFpciBpbiBzZW5zaXRpdmVfcmVzaXN0YW50X3BhaXJzKSB7CiAgc3BsaXQgPC0gc3Ryc3BsaXQocGFpciwgIl92c18iKQogIGNvbnQgPC0gc3BsaXRbWzFdXVsyXQogIGV4cCA8LSBzcGxpdFtbMV1dWzFdCiAgCiAgIyBDcmVhdGVzIGFub3RoZXIgbm90ZWJvb2sgdGhhdCBzaGFyZXMgdGhlIHNhbWUgZW52aXJvbm1lbnQKICBvdXRGaWxlIDwtIHN0cl9pbnRlcnAoImdlbmVyYXRlZC1ub3RlYm9va3MvbWFnaWMtYW5hbHlzaXMtJHtwYWlyfS5odG1sIikKICBwcmludChzdHJfaW50ZXJwKCJDcmVhdGluZyBub3RlYm9vayBmb3IgJHtleHB9IHZzICR7Y29udH0iKSkKICBybWFya2Rvd246OnJlbmRlcignc2luZ2xlLXNlbnNpdGl2ZS1yZXNpc3RhbnQtcGFpci1tYWdpYy1hbmFseXNpcy5SbWQnLCAKICAgICAgICAgICAgICAgICAgICBvdXRwdXRfZmlsZSA9IG91dEZpbGUsIAogICAgICAgICAgICAgICAgICAgIHBhcmFtcyA9IGxpc3QoY29udHJvbENlbGxMaW5lID0gY29udCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBlcmltZW50YWxDZWxsTGluZSA9IGV4cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50bWF0cml4LmFsbCA9IGNvdW50bWF0cml4LmFsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhLmFsbCA9IG1ldGFkYXRhLmFsbCkpCn0KYGBgCgojIyBBbmFseXplIGFsbCBzYW1wbGVzIHRvZ2V0aGVyCgpDcmVhdGUgYSBjbHMgZmlsZSB3aXRoIGNlbGwgbGluZSBjYXRlZ29yaXphdGlvbiBpbmZvcm1hdGlvbgoKYGBge3IgY3JlYXRlIGNscyBmaWxlfQpwb3NzaWJsZV9jYXRlZ29yaWVzIDwtIHVuaXF1ZShtZXRhZGF0YS5hbGwkQ2VsbExpbmUpCmFzc2lnbmVkX2NhdGVnb3JpZXMgPC0gbWV0YWRhdGEuYWxsJENlbGxMaW5lCm51bV9jYXRlZ29yaWVzIDwtIGxlbmd0aChwb3NzaWJsZV9jYXRlZ29yaWVzKQpudW1fc2FtcGxlcyA8LSBsZW5ndGgoYXNzaWduZWRfY2F0ZWdvcmllcykKCmZpbGVDb25uPC1maWxlKCJkYXRhL2FsbF9jZWxsbGluZXMuY2xzIikKd3JpdGVMaW5lcygKICBjKAogICAgc3RyX2ludGVycCgiJHtudW1fc2FtcGxlc31cdCR7bnVtX2NhdGVnb3JpZXN9XHQxIiksCiAgICBzdHJfaW50ZXJwKCIjXHQke3Bhc3RlKHBvc3NpYmxlX2NhdGVnb3JpZXMsIGNvbGxhcHNlPSdcdCcpfSIpLAogICAgc3RyX2ludGVycCgiJHtwYXN0ZShhc3NpZ25lZF9jYXRlZ29yaWVzLCBjb2xsYXBzZT0nXHQnKX0iKSksCiAgZmlsZUNvbm4pCmNsb3NlKGZpbGVDb25uKQpgYGAKCiMjIEZpbHRlciBvdXQgbG93LXJlYWQgZ2VuZXMgdG8gY3JlYXRlIG91ciBiYWNrZ3JvdW5kIGdlbmUgc2V0CgpPbmx5IHJldGFpbiBnZW5lcyBmb3Igd2hpY2ggdGhlcmUgaXMgYSBjZWxsIGxpbmUgdGhhdCBoYWQgYXQgbGVhc3QgMSByZWFkIGZvciB0aGUgZ2VuZSBpbiBhbGwgb2YgaXRzIHJlcGxpY2F0ZXMKCmBgYHtyIGFsbCBiYWNrZ3JvdW5kIGdlbmVzfQpzdHJfaW50ZXJwKCIke25yb3coY291bnRtYXRyaXguYWxsKX0gZ2VuZXMgYmVmb3JlIGZpbHRyYXRpb24uIikKY291bnRtYXRyaXguYWxsLmRmIDwtIGFzLmRhdGEuZnJhbWUoY291bnRtYXRyaXguYWxsKQpmb3Iocm93IGluIDE6bnJvdyhjb3VudG1hdHJpeC5hbGwuZGYpKSB7CiAga2VlcEdlbmUgPC0gRkFMU0UKICAKICAjIGZvciBhdCBsZWFzdCBvbmUgb2YgdGhlIGNlbGwgbGluZXMKICBmb3IgKGNlbGxsaW5lIGluIHVuaXF1ZShtZXRhZGF0YS5hbGwkQ2VsbExpbmUpKSB7CiAgICBhbGxSZWFkIDwtIFRSVUUKICAgIAogICAgIyBhbGwgb2YgdGhlIHJlcGxpY2F0ZXMgbXVzdCBoYXZlIGF0IGxlYXN0IG9uZSByZWFkCiAgICBmb3IoaSBpbiAxOjMpIHsKICAgICAgc2FtcGxlTmFtZSA8LSBzdHJfaW50ZXJwKCIke2NlbGxsaW5lfV9SJHtpfSIpCiAgICAgIGlmIChjb3VudG1hdHJpeC5hbGwuZGZbcm93LCBzYW1wbGVOYW1lXSA8IDEpIHsKICAgICAgICBhbGxSZWFkIDwtIEZBTFNFCiAgICAgIH0KICAgIH0KICAgIAogICAgaWYgKGFsbFJlYWQpIHsKICAgICAga2VlcEdlbmUgPC0gVFJVRQogICAgfQogIH0KICAKICBpZiAoa2VlcEdlbmUpIHsKICAgIGNvdW50bWF0cml4LmFsbC5kZiRTdWZmaWNpZW50UmVhZHNbcm93XSA8LSBUUlVFCiAgfSBlbHNlIHsKICAgIGNvdW50bWF0cml4LmFsbC5kZiRTdWZmaWNpZW50UmVhZHNbcm93XSA8LSBGQUxTRQogIH0KfQoKY291bnRtYXRyaXguYWxsLmZpbHRlcmVkIDwtIGNvdW50bWF0cml4LmFsbC5kZiAlPiUKICBmaWx0ZXIoU3VmZmljaWVudFJlYWRzKQoKc3RyX2ludGVycCgiJHtucm93KGNvdW50bWF0cml4LmFsbC5maWx0ZXJlZCl9IGdlbmVzIGFmdGVyIGZpbHRyYXRpb24uIikKCmJhY2tncm91bmRHZW5lcy5hbGwgPC0gcm93bmFtZXMoY291bnRtYXRyaXguYWxsLmZpbHRlcmVkKQpgYGAKCiMjIERpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzCgpSdW4gRGVzZXEgb24gdGhlIGRhdGEgc2V0LgoKYGBge3Igc2V0dXAgZGVzZXEgYWxsfQojIEhhdmluZyB0aGUgcmVwbGljYXRlIG51bWJlciBpbiB0aGUgZGVzaWduIG1ha2VzIGl0IGEgcGFpcmVkIGRlc2lnbgpkZHMuYWxsIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoCiAgY291bnREYXRhID0gY291bnRtYXRyaXguYWxsLAogIGNvbERhdGEgPSBtZXRhZGF0YS5hbGwsCiAgIyBkZXNpZ24gPSB+IENlbGxMaW5lICsgUmVwbGljYXRlICsgUmVzaXN0YW50KQogIGRlc2lnbiA9IH4gQ2VsbExpbmUgKyBSZXBsaWNhdGUpCmBgYAoKVXNpbmcgYSBMaWtlbGlob29kIFJhdGlvIFRlc3QgcmF0aGVyIHRoYW4gdGhlIFdhbGQgdGVzdCBhbGxvd3MgdXMgdG8gYW5hbHl6ZSBhbGwgY2VsbExpbmVzIGF0IG9uY2UgKHJhdGhlciB0aGFuIGFuYWx5emluZyB0aGVtIHBhaXItd2lzZSkuIFAtdmFsdWVzIGFyZSBkZXRlcm1pbmVkIG9ubHkgYnkgdGhlIGRpZmZlcmVuY2UgaW4gcGVyZm9ybWFuY2Ugb2YgdGhlIGZ1bGwgYW5kIHJlZHVjZWQgbW9kZWxzLiBUaGlzIGFuc3dlcnMgd2hldGhlciB0aGUgY2VsbCBsaW5lIGV4cGxhaW5zIGEgc2lnbmlmaWNhbnQgYW1vdW50IG9mIHZhcmlhdGlvbiBpbiB0aGUgZ2VuZSBleHByZXNzaW9uLiBXZSBjYW4gdGhlbiBleGFtaW5lIGFsbCBjZWxsIGxpbmVzIHRvZ2V0aGVyLgoKYGBge3IgYWxsIGRlc2VxfQojIEZ1bGwgbW9kZWwgaW5jbHVkZXMgIFJlcGxpY2F0ZSArIENlbGxMaW5lOyBSZWR1Y2VkIG1vZGVsIG9ubHkgaW5jbHVkZXMgUmVwbGljYXRlCmRkcy5hbGwgPC0gREVTZXEoZGRzLmFsbCwgdGVzdD0iTFJUIiwKICAgICAgICAgICAgICAgICByZWR1Y2VkID0gfiBSZXBsaWNhdGUpCiAgICAgICAgICAgICAgICAgIyByZWR1Y2VkID0gfiBDZWxsTGluZSArIFJlcGxpY2F0ZSkKYGBgCgojIyBGaWx0ZXIgYW5kIG5vcm1hbGl6ZSBkZXNlcSBvdXRwdXQKCkZpbHRlciBvdXQgdGhlIGxvdyByZWFkIGdlbmVzIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBpbiBvdXIgYmFja2dyb3VuZCBnZW5lIGxpc3QuCmBgYHtyIG92Y2FyIGZpbHRlciBkZXNlcX0KIyBGaWx0ZXIgKHJlY2FsY3VsYXRlcyBwLWFkanVzdGVkIHZhbHVlcyBhdXRvbWF0aWNhbGx5KQpkZHMuYWxsLmZpbHRlcmVkIDwtIHN1YnNldChkZHMuYWxsLCByb3duYW1lcyhkZHMuYWxsKSAlaW4lIGJhY2tncm91bmRHZW5lcy5hbGwpCgojIFB1bGwgb3V0IHJlc3VsdHMKcmVzLmFsbC5scnQuZmlsdGVyZWQgPC0gcmVzdWx0cyhkZHMuYWxsLmZpbHRlcmVkKQpyZXMuYWxsLmxydC5maWx0ZXJlZCA8LSBhcy5kYXRhLmZyYW1lKHJlcy5hbGwubHJ0LmZpbHRlcmVkW29yZGVyKHJlcy5hbGwubHJ0LmZpbHRlcmVkJHBhZGosIGRlY3JlYXNpbmcgPSBGQUxTRSksXSkKCmFzLmRhdGEuZnJhbWUocmVzLmFsbC5scnQuZmlsdGVyZWQpCgojIFB1bGwgb3V0IG9ubHkgc2lnbmlmaWNhbnQgcmVzdWx0cwpzaWcucmVzLmFsbC5scnQuZmlsdGVyZWQgPC0gcmVzLmFsbC5scnQuZmlsdGVyZWQgJT4lIGZpbHRlcihwYWRqIDwgMC4wNSkKc2lnLnJlcy5hbGwubHJ0LmZpbHRlcmVkCgojIFN1YnNldCB0aGUgZGRzIGZvciBzaWduaWZpY2FudCByZXN1bHRzCnNpZ0dlbmVzLmFsbCA8LSByb3duYW1lcyhzaWcucmVzLmFsbC5scnQuZmlsdGVyZWQpCmRkcy5hbGwuZmlsdGVyZWQuc2lnIDwtIHN1YnNldChkZHMuYWxsLmZpbHRlcmVkLCByb3duYW1lcyhkZHMuYWxsLmZpbHRlcmVkKSAlaW4lIHNpZ0dlbmVzLmFsbCkKYGBgCgpOb3JtYWxpemUgdGhlIGRhdGEgdXNpbmcgdGhlIG1lZGlhbiBvZiByYXRpb3MgbWV0aG9kIGFuZCB2c3QgbWV0aG9kcy4gQ2hvc2VuIGJhc2VkIG9uIFt0aGlzIHRyYWluaW5nXShodHRwczovL25iaXN3ZWRlbi5naXRodWIuaW8vd29ya3Nob3AtUk5Bc2VxLzE5MDYvbGFiX2RnZS5odG1sKQoKYGBge3Igbm9ybWFsaXplIHRoZSBkYXRhfQojIE5vcm1hbGl6ZSB1c2luZyB0aGUgbWVkaWFuIG9mIHJhdGlvcyBtZXRob2QsIHdoaWNoIGluY29ycG9yYXRlcyBzZXF1ZW5jaW5nIGRlcHRoIGFuZCBjb21wb3NpdGlvbmFsIGJpYXMKbm9ybWFsaXplZF9jb3VudHMuYWxsLmZpbHRlcmVkIDwtIGNvdW50cyhkZHMuYWxsLmZpbHRlcmVkLCBub3JtYWxpemVkPVRSVUUpCm5vcm1hbGl6ZWRfY291bnRzLmFsbC5scnQuZmlsdGVyZWQuc2lnIDwtIGNvdW50cyhkZHMuYWxsLmZpbHRlcmVkLnNpZywgbm9ybWFsaXplZD1UUlVFKQphcy5kYXRhLmZyYW1lKGNvdW50cyhkZHMuYWxsLmZpbHRlcmVkKSkgIyBub24tbm9ybWFsaXplZAphcy5kYXRhLmZyYW1lKG5vcm1hbGl6ZWRfY291bnRzLmFsbC5maWx0ZXJlZCkgIyBub3JtYWxpemVkCgp3cml0ZS50YWJsZSgKICBhcy5kYXRhLmZyYW1lKG5vcm1hbGl6ZWRfY291bnRzLmFsbC5maWx0ZXJlZCksCiAgZmlsZT0iZGF0YS9hbGxfZmlsdGVyZWRfbm9ybWFsaXplZF9jb3VudHMudHh0IiwKICBzZXA9Ilx0IiwKICBxdW90ZT1GLAogIGNvbC5uYW1lcz1OQSkKCndyaXRlLnRhYmxlKAogIGFzLmRhdGEuZnJhbWUobm9ybWFsaXplZF9jb3VudHMuYWxsLmxydC5maWx0ZXJlZC5zaWcpLAogIGZpbGU9ImRhdGEvYWxsX2ZpbHRlcmVkX3NpZ19ub3JtYWxpemVkX2NvdW50cy50eHQiLAogIHNlcD0iXHQiLAogIHF1b3RlPUYsCiAgY29sLm5hbWVzPU5BKQoKIyBOb3JtYWxpemUgdXNpbmcgdnN0LCB3aGljaCByZXN1bHRzIGluIHNpbWlsYXIgdmFyaWFuY2UgYWNyb3NzIHNhbXBsZXMuIFRoaXMgaXMgbmVlZGVkIGZvciBQQ0EgYW5hbHlzaXMKdnN0LmRkcy5hbGwuZmlsdGVyZWQgPC0gdnN0KGRkcy5hbGwuZmlsdGVyZWQpCnZzdC5kZHMuYWxsLmZpbHRlcmVkLnNpZyA8LSB2c3QoZGRzLmFsbC5maWx0ZXJlZC5zaWcpICMgVE9ETzogU2hvdWxkIEkgdGFrZSB2c3Qgb2Ygc2lnbmlmaWNhbnQgcGVha3Mgb3Igc3Vic2V0IHRoZSBzaWduaWZpY2FudCBwZWFrcyBmcm9tIHRoZSB2c3Qgb2YgZnVsbCBkYXRhPwpgYGAKCiMjIFBDQSBQbG90cwoKQWxsIGJhY2tncm91bmQgZ2VuZXMuIFRoaXMgcGxvdHMgdGhlIHZzdCBvZiB0aGUgY291bnRzLgoKYGBge3Igbm9ybWFsaXplZCBQQ0EgLSBhbGwgYmFja2dyb3VuZCBnZW5lc30KcGNhRGF0YSA8LSBwbG90UENBKHZzdC5kZHMuYWxsLmZpbHRlcmVkLCBpbnRncm91cCA9IGMoIkNlbGxMaW5lIiwgIlNob3J0TmFtZSIpLCByZXR1cm5EYXRhID0gVFJVRSkKcGVyY2VudFZhciA8LSByb3VuZCgxMDAgKiBhdHRyKHBjYURhdGEsICJwZXJjZW50VmFyIikpCmdncGxvdChwY2FEYXRhLCBhZXMoUEMxLCBQQzIsIGNvbG9yID0gQ2VsbExpbmUsIGxhYmVsID0gU2hvcnROYW1lKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX3RleHQoaGp1c3QgPSAwLCB2anVzdCA9IDApICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyWzFdLCAiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhclsyXSwgIiUgdmFyaWFuY2UiKSkgKwogIGNvb3JkX2ZpeGVkKCkKYGBgCgpPbmx5IHNpZ25pZmljYW50IGdlbmVzLiBUaGlzIHBsb3RzIHRoZSB2c3Qgb2YgdGhlIGNvdW50cy4KCmBgYHtyIG5vcm1hbGl6ZWQgUENBIC0gb25seSBzaWduaWZpY2FudCBmb3IgcmVzaXN0YW5jZSBnZW5lc30KcGNhRGF0YSA8LSBwbG90UENBKHZzdC5kZHMuYWxsLmZpbHRlcmVkLnNpZywgaW50Z3JvdXAgPSBjKCJDZWxsTGluZSIsICJTaG9ydE5hbWUiKSwgcmV0dXJuRGF0YSA9IFRSVUUpCnBlcmNlbnRWYXIgPC0gcm91bmQoMTAwICogYXR0cihwY2FEYXRhLCAicGVyY2VudFZhciIpKQpnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBjb2xvciA9IENlbGxMaW5lLCBsYWJlbCA9IFNob3J0TmFtZSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgZ2VvbV90ZXh0KGhqdXN0ID0gMCwgdmp1c3QgPSAwKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhclsxXSwgIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIsIHBlcmNlbnRWYXJbMl0sICIlIHZhcmlhbmNlIikpICsKICBjb29yZF9maXhlZCgpCmBgYAoKIyBDbHVzdGVyIHVzaW5nIExlaWRlbiBjbHVzdGVyaW5nIChzY3JpcHQgY291cnRlc3kgb2YgQXZ0YXIpCgpgcHl0aG9uIHNjcmlwdHMvTGVpZGVuX2NsdXN0ZXJfZ2VuZXMucHlgClByb3ZpZGUgdGhlIGZpbGVzICBgZGF0YS9hbGxfZmlsdGVyZWRfc2lnX25vcm1hbGl6ZWRfY291bnRzLnR4dGAgYW5kIGBkYXRhL2FsbF9jZWxsbGluZXMuY2xzYApXaGVuIHByb21wdGVkLCBzZWxlY3QgInllcyIgZm9yIGNlbnRlcmluZyB0aGUgZGF0YSBhbmQgdXNpbmcgbWVhbnMgb2YgY29uZGl0aW9ucy4gU2VsZWN0ICJubyIgZm9yIHRha2luZyBhIHN1YnNldCBvZiB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgKHdlIGhhdmUgYWxyZWFkeSBwZXJmb3JtZWQgdGhpcyBzdWJzZXQpLiBEZWZhdWx0IHJlc29sdXRpb24gaXMgZmluZS4KIApDb3B5IG91dHB1dCBpbnRvIGdlbmVfY2x1c3RlcnMgZm9sZGVyOiAKYGNwIGRhdGEvYWxsX2ZpbHRlcmVkX3NpZ19ub3JtYWxpemVkX2NvdW50c19jbHVzdGVycy9jbHVzdGVyc19jZW50ZXJlZC5wZGYgZ2VuZV9jbHVzdGVycy9hbGxfZ2VuZV9jbHVzdGVyc19jZW50ZXJlZC5wZGZgCmBjcCBkYXRhL2FsbF9maWx0ZXJlZF9zaWdfbm9ybWFsaXplZF9jb3VudHNfY2x1c3RlcnMvZ2VuZV9jbHVzdGVyX2xpc3RzLlRTViBnZW5lX2NsdXN0ZXJzL2FsbF9nZW5lX2NsdXN0ZXJfc19jZW50ZXJlZC5wZGZfbGlzdHMuVFNWYAoKVGhpcyB3YXMgZm9yIGFsbCBpc29saW5lcyBhcyB3ZWxsIGFzIHRoZSBmdWxsIGRhdGEgc2V0LiBXZSB3aWxsIGJlIGV4YW1pbmluZyB0aGUgaXNvZ2VuaWMgbGluZXMgaW5kaXZpZHVhbGx5IHVzaW5nIE1hZ2ljLiBXZSB1c2VkIGEgcmVzb2x1dGlvbiBvZiAwLjEgdG8gbWF4aW1pemUgY29oZXJlbnQgY2x1c3RlcmluZwoKIyBBbmFseXplIGNsdXN0ZXJzIGFjcm9zcyBzZW5zaXRpdmUtcmVzaXN0YW50IHBhaXJzCgojIyBDcmVhdGUgdGhlIG1hZ2ljIGlucHV0CgpgYGB7ciBjcmVhdGUgbWFnaWMgaW5wdXR9CmZvciAocGFpciBpbiBzZW5zaXRpdmVfcmVzaXN0YW50X3BhaXJzKSB7CiAgCiAgCiAgIyBMb2FkIHRoZSBkaWZmZXJlbnRpYWwgcmVzdWx0cwogIGxvYWRlZF90byA8LSBsb2FkKHN0cl9pbnRlcnAoIlJkYXRhLyR7cGFpcn1fcmVzX2ZpbHRlcmVkLlJEYXRhIikpCiAgcGFpci5kaWZmZXJlbnRpYWwucmVzdWx0cyA8LSBnZXQobG9hZGVkX3RvKQogIHBhaXIuZGlmZmVyZW50aWFsLnJlc3VsdHMkZ2VuZSA8LSByb3duYW1lcyhwYWlyLmRpZmZlcmVudGlhbC5yZXN1bHRzKQogIAogIHByaW50KHBhaXIpCiAgcHJpbnQocGFpci5kaWZmZXJlbnRpYWwucmVzdWx0c1tvcmRlcihwYWlyLmRpZmZlcmVudGlhbC5yZXN1bHRzJHBhZGopLF0pCiAgCiAgIyBTZXBhcmF0ZSB1cCBhbmQgZG93biBnZW5lcwogIHBhaXJfdXBfZ2VuZXMgPC0gcGFpci5kaWZmZXJlbnRpYWwucmVzdWx0cyAlPiUgZmlsdGVyKGxvZzJGb2xkQ2hhbmdlID4gMCAmIHBhZGogPCAwLjA1KQogIHBhaXJfZG93bl9nZW5lcyA8LSBwYWlyLmRpZmZlcmVudGlhbC5yZXN1bHRzICU+JSBmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPCAwICYgcGFkaiA8IDAuMDUpCgogICMgUmVhZCBpbiBiYWNrZ3JvdW5kIGdlbmVzCiAgcGFpcl9maWx0ZXJlZF9ub3JtYWxpemVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHJlYWQudGFibGUoc3RyX2ludGVycCgiZGF0YS8ke3BhaXJ9X2ZpbHRlcmVkX25vcm1hbGl6ZWRfY291bnRzLnR4dCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxKSkKICBwYWlyX2JhY2tncm91bmRfZ2VuZXMgPC0gcm93Lm5hbWVzKHBhaXJfZmlsdGVyZWRfbm9ybWFsaXplZF9jb3VudHMpCiAgcGFpcl91cF9nZW5lcyA8LSBwYWlyX3VwX2dlbmVzJGdlbmVbb3JkZXIocGFpcl91cF9nZW5lcyRnZW5lKV0KICBwYWlyX2Rvd25fZ2VuZXMgPC0gcGFpcl9kb3duX2dlbmVzJGdlbmVbb3JkZXIocGFpcl9kb3duX2dlbmVzJGdlbmUpXQoKICAjIENvbWJpbmUgdG8gZm9ybSBtYWdpYyBpbnB1dAogIHBhaXJfbWFnaWNfaW5wdXQgPC0gZGF0YS5mcmFtZShiYWNrZ3JvdW5kX2dlbmVzID0gcGFpcl9iYWNrZ3JvdW5kX2dlbmVzKQogIHBhaXJfbWFnaWNfaW5wdXRbMTpsZW5ndGgocGFpcl91cF9nZW5lcyksICJ1cF9pbl9yZXNpc3RhbnQiXSA8LSBwYWlyX3VwX2dlbmVzCiAgcGFpcl9tYWdpY19pbnB1dFsxOmxlbmd0aChwYWlyX2Rvd25fZ2VuZXMpLCAiZG93bl9pbl9yZXNpc3RhbnQiXSA8LSBwYWlyX2Rvd25fZ2VuZXMKCiAgcHJpbnQocGFpcl9tYWdpY19pbnB1dCkKCiAgd3JpdGUudGFibGUocGFpcl9tYWdpY19pbnB1dCwKICAgICAgICAgICAgICBmaWxlID0gc3RyX2ludGVycCgiZGF0YS8ke3BhaXJ9X21hZ2ljX2lucHV0LnR4dCIpLAogICAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsCiAgICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgbmEgPSAiIiwKICAgICAgICAgICAgICBzZXAgPSAiXHQiKQp9CmBgYAoKPCEtLSAjIEFuYWx5emUgY2x1c3RlcnMgYWNyb3NzIGFsbCBpc29saW5lcyAtLT4KCjwhLS0gIyMgU2VsZWN0IHRoZSBncm91cHMgdGhhdCBhcmUgZGVlbWVkICJpbnRlcmVzdGluZyIgLS0+Cgo8IS0tIE1hbnVhbGx5IHNlbGVjdGVkIGFsbCByZXNpc3RhbnQgbGluZXMgZ29pbmcgdXAgb3IgYWxsIHJlc2lzdGFudCBsaW5lcyBnb2luZyBkb3duLCBjb25zaWRlcmluZyBlcnJvciBiYXJzIC0tPgoKPCEtLSBgYGB7ciBpbnRlcmVzdGluZyBjbHVzdGVyc30gLS0+CjwhLS0gICBPVkNBUjNfdXBfZ3JvdXBzIDwtIGMoImdyZWVuIiwgImJsYWNrIikgLS0+CjwhLS0gICBPVkNBUjNfZG93bl9ncm91cHMgPC0gYygicHVycGxlIiwgImluZGlnbyIsICJncmV5IikgLS0+CjwhLS0gICBPVkNBUjRfdXBfZ3JvdXBzIDwtIGMoInJlZCIsICJncmVlbiIpIC0tPgo8IS0tICAgT1ZDQVI0X2Rvd25fZ3JvdXBzIDwtIGMoImJyb3duIiwgImJsYWNrIiwgImdyZXkiKSAtLT4KPCEtLSAgIFBFT191cF9ncm91cHMgPC0gYygiYmx1ZSIsICJncmVlbiIpIC0tPgo8IS0tICAgUEVPX2Rvd25fZ3JvdXBzIDwtIGMoInJlZCIsICJicm93biIsICJza3libHVlIikgLS0+CjwhLS0gICBQRUFfdXBfZ3JvdXBzIDwtIGMoImdyZXkiKSAtLT4KPCEtLSAgIFBFQV9kb3duX2dyb3VwcyA8LSBjKCJicm93biIsICJibGFjayIsICJ0ZWFsIiwgImFxdWEiLCAibGltZSIpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gIyMgQ3JlYXRlIHRoZSBtYWdpYyBpbnB1dCAtLT4KCjwhLS0gYGBge3IgY3JlYXRlIG1hZ2ljIGlucHV0fSAtLT4KPCEtLSBmb3IgKGlzb2xpbmUgaW4gYygiT1ZDQVIzIiwgIk9WQ0FSNCIsICJQRUEiLCAiUEVPIikpIHsgLS0+CjwhLS0gICBpc29saW5lX3VwX2dyb3VwcyA8LSBnZXQoc3RyX2ludGVycCgiJHtpc29saW5lfV91cF9ncm91cHMiKSkgLS0+CjwhLS0gICBpc29saW5lX2Rvd25fZ3JvdXBzIDwtIGdldChzdHJfaW50ZXJwKCIke2lzb2xpbmV9X2Rvd25fZ3JvdXBzIikpIC0tPgo8IS0tICAgaXNvbGluZV9jbHVzdGVycyA8LSBhcy5kYXRhLmZyYW1lKHJlYWQudGFibGUoc3RyX2ludGVycCgiZ2VuZV9jbHVzdGVycy8ke2lzb2xpbmV9X3JlczAuMV9nZW5lX2NsdXN0ZXJzX2xpc3RzLlRTViIpLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUpKSAtLT4KPCEtLSAgICMgQ29tYmluZSB1cCBjbHVzdGVycyAtLT4KPCEtLSAgIGlzb2xpbmVfdXBfZ2VuZXMgPC0gZGF0YS5mcmFtZSh1cF9pbl9yZXNpc3RhbnQgPSB1bmxpc3QoaXNvbGluZV9jbHVzdGVyc1ssIGlzb2xpbmVfdXBfZ3JvdXBzXSkpIC0tPgo8IS0tICAgcm93Lm5hbWVzKGlzb2xpbmVfdXBfZ2VuZXMpIDwtIE5VTEwgLS0+CjwhLS0gICBjb2xuYW1lcyhpc29saW5lX3VwX2dlbmVzKSA8LSBjKCJ1cF9pbl9yZXNpc3RhbnQiKSAtLT4KPCEtLSAgIGlzb2xpbmVfdXBfZ2VuZXMgPC0gaXNvbGluZV91cF9nZW5lc1tpc29saW5lX3VwX2dlbmVzJHVwX2luX3Jlc2lzdGFudCAhPSAiIixdIC0tPgoKPCEtLSAgICMgQ29tYmluZSBkb3duIGNsdXN0ZXJzIC0tPgo8IS0tICAgaXNvbGluZV9kb3duX2dlbmVzIDwtIGRhdGEuZnJhbWUoZG93bl9pbl9yZXNpc3RhbnQgPSB1bmxpc3QoaXNvbGluZV9jbHVzdGVyc1ssIGlzb2xpbmVfZG93bl9ncm91cHNdKSkgLS0+CjwhLS0gICByb3cubmFtZXMoaXNvbGluZV9kb3duX2dlbmVzKSA8LSBOVUxMIC0tPgo8IS0tICAgY29sbmFtZXMoaXNvbGluZV9kb3duX2dlbmVzKSA8LSBjKCJkb3duX2luX3Jlc2lzdGFudCIpIC0tPgo8IS0tICAgaXNvbGluZV9kb3duX2dlbmVzIDwtIGlzb2xpbmVfZG93bl9nZW5lc1tpc29saW5lX2Rvd25fZ2VuZXMkZG93bl9pbl9yZXNpc3RhbnQgIT0gIiIsXSAtLT4KCjwhLS0gICAjIFJlYWQgaW4gYmFja2dyb3VuZCBnZW5lcyAtLT4KPCEtLSAgIGlzb2xpbmVfZmlsdGVyZWRfbm9ybWFsaXplZF9jb3VudHMgPC0gYXMuZGF0YS5mcmFtZShyZWFkLnRhYmxlKHN0cl9pbnRlcnAoImRhdGEvJHtpc29saW5lfV9maWx0ZXJlZF9ub3JtYWxpemVkX2NvdW50cy50eHQiKSwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSkpIC0tPgo8IS0tICAgaXNvbGluZV9iYWNrZ3JvdW5kX2dlbmVzIDwtIHJvdy5uYW1lcyhpc29saW5lX2ZpbHRlcmVkX25vcm1hbGl6ZWRfY291bnRzKSAtLT4KCjwhLS0gICAjIENvbWJpbmUgdG8gZm9ybSBtYWdpYyBpbnB1dCAtLT4KPCEtLSAgIGlzb2xpbmVfbWFnaWNfaW5wdXQgPC0gZGF0YS5mcmFtZShiYWNrZ3JvdW5kX2dlbmVzID0gaXNvbGluZV9iYWNrZ3JvdW5kX2dlbmVzKSAtLT4KPCEtLSAgIGlzb2xpbmVfbWFnaWNfaW5wdXRbMTpsZW5ndGgoaXNvbGluZV91cF9nZW5lcyksICJ1cF9pbl9yZXNpc3RhbnQiXSA8LSBpc29saW5lX3VwX2dlbmVzIC0tPgo8IS0tICAgaXNvbGluZV9tYWdpY19pbnB1dFsxOmxlbmd0aChpc29saW5lX2Rvd25fZ2VuZXMpLCAiZG93bl9pbl9yZXNpc3RhbnQiXSA8LSBpc29saW5lX2Rvd25fZ2VuZXMgLS0+Cgo8IS0tICAgd3JpdGUudGFibGUoaXNvbGluZV9tYWdpY19pbnB1dCwgLS0+CjwhLS0gICAgICAgICAgICAgICBmaWxlID0gc3RyX2ludGVycCgiZGF0YS8ke2lzb2xpbmV9X21hZ2ljX2lucHV0LnR4dCIpLCAtLT4KPCEtLSAgICAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsIC0tPgo8IS0tICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UsIC0tPgo8IS0tICAgICAgICAgICAgICAgbmEgPSAiIiwgLS0+CjwhLS0gICAgICAgICAgICAgICBzZXAgPSAiXHQiKSAtLT4KPCEtLSB9IC0tPgo8IS0tIGBgYCAtLT4KCiMgUnVuIE1hZ2ljCgojIyBVc2UgdGhlIGBydW5fbWFnaWMuc2hgIHNjcmlwdC4KCiMjIENvbWJpbmluZyBtYWdpYyBvdXRwdXQKIlRoZSBTY29yZSBjb21iaW5lcyB0aGUgY29ycmVjdGVkIHAgdmFsdWUgZnJvbSB0aGlzIHRlc3QgYW5kIGEgbWVhc3VyZSBvZiBob3cgc2tld2VkIHRoZSBjaGlwIHNpZ25hbHMgYXJlIHRvd2FyZHMgaGlnaCB2YWx1ZXMgaW4gdGhlIHF1ZXJ5IHZlcnN1cyBiYWNrZ3JvdW5kIGxpc3RzIgoKIyMjIENvbWJpbmUgcGVyIHNlbnNpdGl2ZS1yZXNpc3RhbnQgcGFpcgoKYGBge3IgY29tYmluZSBtYWdpYyBvdXRwdXR9CmFsbF9zaWdfdXBfYWNyb3NzX3BhaXJzX3RmcyA8LSBjKCkKYWxsX3NpZ19kb3duX2Fjcm9zc19wYWlyc190ZnMgPC0gYygpCgojIFJlYWQgaW4gbWFnaWMgb3V0cHV0IGZvciBlYWNoIHBhaXIKZm9yIChwYWlyIGluIHNlbnNpdGl2ZV9yZXNpc3RhbnRfcGFpcnMpIHsKICBmb3IgKGRpciBpbiBjKCJ1cCIsICJkb3duIikpIHsKICAgIHBhaXJfdGZzIDwtIGFzLmRhdGEuZnJhbWUoCiAgICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2ludGVycCgibWFnaWNfb3V0cHV0LyR7cGFpcn1fb3V0cHV0LyR7ZGlyfV9pbl9yZXNpc3RhbnQvJHtkaXJ9X2luX3Jlc2lzdGFudF9zdW1tYXJ5Lnhsc3giKSkpCiAgICBwYWlyX3RmcyA8LSBwYWlyX3Rmc1twYWlyX3RmcyRwYWRqIDwgMC41LF0gIyBJZiBwYWRqID4gMC41IHRoZW4gdGhpcyBpc24ndCByZWFsbHkgdXAKICAgIHBhaXJfdGZzX3NpZyA8LSBwYWlyX3Rmc1twYWlyX3RmcyRwYWRqIDwgMC4wNSxdCiAgCiAgICBhc3NpZ24oc3RyX2ludGVycCgiJHtwYWlyfV8ke2Rpcn1fdGZzIiksIHBhaXJfdGZzLCBwb3MgPSAxKQogICAgYXNzaWduKHN0cl9pbnRlcnAoIiR7cGFpcn1fJHtkaXJ9X3Rmc19zaWciKSwgcGFpcl90ZnNfc2lnLCBwb3MgPSAxKQogICAgCiAgICBpZiAoZGlyID09ICJ1cCIpIHsKICAgICAgYWxsX3NpZ191cF9hY3Jvc3NfcGFpcnNfdGZzIDwtIGxpc3QuYXBwZW5kKGFsbF9zaWdfdXBfYWNyb3NzX3BhaXJzX3RmcywgcGFpcl90ZnNfc2lnJFRGKQogICAgfSBlbHNlIGlmIChkaXIgPT0gImRvd24iKSB7CiAgICAgIGFsbF9zaWdfZG93bl9hY3Jvc3NfcGFpcnNfdGZzIDwtIGxpc3QuYXBwZW5kKGFsbF9zaWdfZG93bl9hY3Jvc3NfcGFpcnNfdGZzLCBwYWlyX3Rmc19zaWckVEYpCiAgICB9IGVsc2UgewogICAgICBwcmludChzdHJfaW50ZXJwKCJJU1NVRSEgZGlyIG5vdCB2YWxpZDogJHtkaXJ9IikpCiAgICB9CiAgfQp9CgojIEFsbCB0ZnMgdGhhdCBhcmUgc2lnbmlmaWNhbnQgaW4gYXQgbGVhc3Qgb25lIGlzb2xpbmUKY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duIDwtIGRhdGEuZnJhbWUoVEYgPSB1bmlxdWUoYWxsX3NpZ19kb3duX2Fjcm9zc19wYWlyc190ZnMpKQpjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwIDwtIGRhdGEuZnJhbWUoVEYgPSB1bmlxdWUoYWxsX3NpZ191cF9hY3Jvc3NfcGFpcnNfdGZzKSkKCmZvciAocGFpciBpbiBzZW5zaXRpdmVfcmVzaXN0YW50X3BhaXJzKSB7CiAgcGFpcl91cF90ZnMgPC0gZ2V0KHN0cl9pbnRlcnAoIiR7cGFpcn1fdXBfdGZzIikpCiAgcGFpcl9hZGRpdGlvbl91cCA8LSBkYXRhLmZyYW1lKHBhaXJfdXBfdGZzJFRGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWlyX3VwX3RmcyRTY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFpcl91cF90ZnMkcGFkaikKCiAgY29sbmFtZXMocGFpcl9hZGRpdGlvbl91cCkgPC0gYygiVEYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfaW50ZXJwKCIke3BhaXJ9X3VwX3Njb3JlIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9pbnRlcnAoIiR7cGFpcn1fdXBfcGFkaiIpKQoKICBwYWlyX2Rvd25fdGZzIDwtIGdldChzdHJfaW50ZXJwKCIke3BhaXJ9X2Rvd25fdGZzIikpCgogIHBhaXJfYWRkaXRpb25fZG93biA8LSBkYXRhLmZyYW1lKHBhaXJfZG93bl90ZnMkVEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFpcl9kb3duX3RmcyRTY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWlyX2Rvd25fdGZzJHBhZGopCgogIGNvbG5hbWVzKHBhaXJfYWRkaXRpb25fZG93bikgPC0gYygiVEYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9pbnRlcnAoIiR7cGFpcn1fZG93bl9zY29yZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9pbnRlcnAoIiR7cGFpcn1fZG93bl9wYWRqIikpCgogICMgQWRkIHRoZSBpbmZvIGZvciB1cCBhbmQgZG93biBhY3Jvc3MgYWxsIHBhaXJzIHJlZ2FyZGxlc3Mgb2Ygc2lnbmlmaWNhbmNlCiAgaWYgKG5yb3cocGFpcl9hZGRpdGlvbl91cCkgPiAwKSB7CiAgICBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwIDwtIGxlZnRfam9pbihjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFpcl9hZGRpdGlvbl91cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIlRGIikKICAgIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93biA8LSBsZWZ0X2pvaW4oY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWlyX2FkZGl0aW9uX3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJURiIpCiAgfQoKICBpZiAobnJvdyhwYWlyX2FkZGl0aW9uX2Rvd24pID4gMCkgewogICAgY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cCA8LSBsZWZ0X2pvaW4oY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhaXJfYWRkaXRpb25fZG93biwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIlRGIikKICAgIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93biA8LSBsZWZ0X2pvaW4oY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWlyX2FkZGl0aW9uX2Rvd24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIlRGIikKICB9Cn0KCiMgQ291bnQgdGhlIG51bWJlciBvZiBpc29saW5lcyB0aGF0IHdlcmUgc2lnbmlmaWNhbnRseSB1cC9kb3duIGluIGVhY2ggVEYKZm9yIChyb3cgaW4gMTpucm93KGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXApKSB7CiAgbnVtX3NpZ191cCA8LSAwCiAgZm9yIChwYWlyIGluIHNlbnNpdGl2ZV9yZXNpc3RhbnRfcGFpcnMpIHsKICAgIGNvbF9uYW1lIDwtIHBhc3RlMChwYWlyLCAiX3VwX3BhZGoiKQogICAgcGFkaiA8LSBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwW3JvdywgY29sX25hbWVdCiAgICBpZiAoIWlzLm5hKHBhZGopICYgcGFkaiA8IDAuMDUpIHsKICAgICAgbnVtX3NpZ191cCA8LSBudW1fc2lnX3VwICsgMQogICAgfQogIH0KCiAgbnVtX3NpZ19kb3duIDwtIDAKICBmb3IgKHBhaXIgaW4gc2Vuc2l0aXZlX3Jlc2lzdGFudF9wYWlycykgewogICAgY29sX25hbWUgPC0gcGFzdGUwKHBhaXIsICJfZG93bl9wYWRqIikKICAgIHBhZGogPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cFtyb3csIGNvbF9uYW1lXQogICAgaWYgKCFpcy5uYShwYWRqKSAmIHBhZGogPCAwLjA1KSB7CiAgICAgIG51bV9zaWdfZG93biA8LSBudW1fc2lnX2Rvd24gKyAxCiAgICB9CiAgfQoKICBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwW3JvdywgIm51bV9wYWlyc19zaWdfdXAiXSA8LSBudW1fc2lnX3VwCiAgY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cFtyb3csICJudW1fcGFpcnNfc2lnX2Rvd24iXSA8LSBudW1fc2lnX2Rvd24KfQoKIyBDb3VudCB0aGUgbnVtYmVyIG9mIGlzb2xpbmVzIHRoYXQgd2VyZSBzaWduaWZpY2FudGx5IHVwL2Rvd24gaW4gZWFjaCBURgpmb3IgKHJvdyBpbiAxOm5yb3coY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duKSkgewogIG51bV9zaWdfdXAgPC0gMAogIGZvciAocGFpciBpbiBzZW5zaXRpdmVfcmVzaXN0YW50X3BhaXJzKSB7CiAgICBjb2xfbmFtZSA8LSBwYXN0ZTAocGFpciwgIl91cF9wYWRqIikKICAgIHBhZGogPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duW3JvdywgY29sX25hbWVdCiAgICBpZiAoIWlzLm5hKHBhZGopICYgcGFkaiA8IDAuMDUpIHsKICAgICAgbnVtX3NpZ191cCA8LSBudW1fc2lnX3VwICsgMQogICAgfQogIH0KCiAgbnVtX3NpZ19kb3duIDwtIDAKICBmb3IgKHBhaXIgaW4gc2Vuc2l0aXZlX3Jlc2lzdGFudF9wYWlycykgewogICAgY29sX25hbWUgPC0gcGFzdGUwKHBhaXIsICJfZG93bl9wYWRqIikKICAgIHBhZGogPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duW3JvdywgY29sX25hbWVdCiAgICBpZiAoIWlzLm5hKHBhZGopICYgcGFkaiA8IDAuMDUpIHsKICAgICAgbnVtX3NpZ19kb3duIDwtIG51bV9zaWdfZG93biArIDEKICAgIH0KICB9CgogIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bltyb3csICJudW1fcGFpcnNfc2lnX3VwIl0gPC0gbnVtX3NpZ191cAogIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bltyb3csICJudW1fcGFpcnNfc2lnX2Rvd24iXSA8LSBudW1fc2lnX2Rvd24KfQoKIyBSZW9yZGVyIGNvbHVtbnMKY29sX25hbWVzIDwtIGMoIlRGIiwgIm51bV9wYWlyc19zaWdfdXAiLCAibnVtX3BhaXJzX3NpZ19kb3duIikKZm9yIChkaXIgaW4gYygidXAiLCAiZG93biIpKSB7CiAgZm9yIChwYWlyIGluIHNlbnNpdGl2ZV9yZXNpc3RhbnRfcGFpcnMpIHsKICAgIGNvbF9uYW1lIDwtIHBhc3RlMChwYWlyLCAiXyIsIGRpciwgIl9zY29yZSIpCiAgICBjb2xfbmFtZXMgPC0gYXBwZW5kKGNvbF9uYW1lcywgY29sX25hbWUpCiAgICBjb2xfbmFtZSA8LSBwYXN0ZTAocGFpciwgIl8iLCBkaXIsICJfcGFkaiIpCiAgICBjb2xfbmFtZXMgPC0gYXBwZW5kKGNvbF9uYW1lcywgY29sX25hbWUpCiAgfQp9Cgpyb3duYW1lcyhjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwKSA8LSBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwJFRGCmNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXAgPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cFssIGNvbF9uYW1lc10KCnJvd25hbWVzKGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bikgPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duJFRGCmNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93biA8LSBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd25bLCBjb2xfbmFtZXNdCgojIFNvcnQgYnkgbnVtIHNpZ25pZmljYW50CmNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXAgPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cFtvcmRlcihjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwJG51bV9wYWlyc19zaWdfdXAsIGRlY3JlYXNpbmc9VFJVRSksXQpjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd24gPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duW29yZGVyKGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93biRudW1fcGFpcnNfc2lnX2Rvd24sIGRlY3JlYXNpbmc9VFJVRSksXQoKIyBUYWJsZXMgaW5jbHVkZSBURiBpbmZvIGFjcm9zcyBhbGwgaXNvbGluZXMgZm9yIGVhY2ggdGYgdGhhdCBpcyB1cC9kb3duIHJlZ3VsYXRlZCBzaWduaWZpY2FudGx5IGluIGF0IGxlYXN0IG9uZSBpc29saW5lCnByaW50KGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXApCnByaW50KGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bikKCndyaXRlLnRhYmxlKGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXAsCiAgICAgICAgICAgIGZpbGUgPSBzdHJfaW50ZXJwKCJkaWZmZXJlbnRpYWxfdGZzL2NvbWJpbmVkX21hZ2ljX291dHB1dF91cF9zaWdfc2Vuc2l0aXZlLXJlc2lzdGFudC1wYWlycy50eHQiKSwKICAgICAgICAgICAgcXVvdGUgPSBGQUxTRSwKICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgIG5hID0gIiIsCiAgICAgICAgICAgIHNlcCA9ICJcdCIpCgp3cml0ZS50YWJsZShjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd24sCiAgICAgICAgICAgIGZpbGUgPSBzdHJfaW50ZXJwKCJkaWZmZXJlbnRpYWxfdGZzL2NvbWJpbmVkX21hZ2ljX291dHB1dF9kb3duX3NpZ19zZW5zaXRpdmUtcmVzaXN0YW50LXBhaXJzLnR4dCIpLAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLAogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgbmEgPSAiIiwKICAgICAgICAgICAgc2VwID0gIlx0IikKYGBgCiMjIE9ubHkgY29uc2lkZXIgdW5pZGlyZWN0aW9uYWwgcmVzdWx0cy4KCmBgYHtyfQpmb3IgKHBhaXIgaW4gc2Vuc2l0aXZlX3Jlc2lzdGFudF9wYWlycykgewogIAogIHBhaXJfdXBfdGZzX3NpZyA8LSBnZXQoc3RyX2ludGVycCgiJHtwYWlyfV91cF90ZnNfc2lnIikpCiAgcGFpcl9kb3duX3Rmc19zaWcgPC0gZ2V0KHN0cl9pbnRlcnAoIiR7cGFpcn1fZG93bl90ZnNfc2lnIikpCiAgCiAgIyBTdWJzZXQgdW5pZGlyZWN0aW9uYWwgcmVzdWx0cwogIHBhaXJfc2lnX3VwX29ubHlfdGZzIDwtIHBhaXJfdXBfdGZzX3NpZ1shKHBhaXJfdXBfdGZzX3NpZyRURiAlaW4lIHBhaXJfZG93bl90ZnNfc2lnJFRGKSwgXQogIHBhaXJfc2lnX2Rvd25fb25seV90ZnMgPC0gcGFpcl9kb3duX3Rmc19zaWdbIShwYWlyX2Rvd25fdGZzX3NpZyRURiAlaW4lIHBhaXJfdXBfdGZzX3NpZyRURiksIF0KICAKICAjIFNhdmUgUiBkYXRhCiAgYXNzaWduKHN0cl9pbnRlcnAoIiR7cGFpcn1fc2lnX3VwX29ubHlfdGZzIiksIHBhaXJfc2lnX3VwX29ubHlfdGZzKQogIGFzc2lnbihzdHJfaW50ZXJwKCIke3BhaXJ9X3NpZ19kb3duX29ubHlfdGZzIiksIHBhaXJfc2lnX2Rvd25fb25seV90ZnMpCiAgCiAgIyBXcml0ZSB0byBmaWxlCiAgd3JpdGUudGFibGUocGFpcl9zaWdfdXBfb25seV90ZnMsCiAgICAgICAgICAgIHN0cl9pbnRlcnAoImRpZmZlcmVudGlhbF90ZnMvJHtwYWlyfV90ZnNfb25seV9zaWdfdXAudHh0IiksCiAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICBjb2wubmFtZXMgPSBUUlVFLAogICAgICAgICAgICBzZXAgPSAiXHQiKQogIHdyaXRlLnRhYmxlKHBhaXJfc2lnX2Rvd25fb25seV90ZnMsCiAgICAgICAgICAgIHN0cl9pbnRlcnAoImRpZmZlcmVudGlhbF90ZnMvJHtwYWlyfV90ZnNfb25seV9zaWdfZG93bi50eHQiKSwKICAgICAgICAgICAgcXVvdGUgPSBGQUxTRSwKICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgIGNvbC5uYW1lcyA9IFRSVUUsCiAgICAgICAgICAgIHNlcCA9ICJcdCIpCn0KYGBgCgpDcmVhdGUgYW4gdXBzZXQgcGxvdCBvZiB0aGUgVEZzIHRoYXQgd2VyZSBzaWduaWZpY2FudCBpbiBlaXRoZXIgdXAgb3IgZG93biBleHByZXNzZWQgZ2VuZXMgKGJ1dCBub3QgYm90aCkgd2l0aGluIGEgZ2l2ZW4gc2Vuc2l0aXZlL3Jlc2lzdGFudCBwYWlyLgoKYGBge3IgdXBzZXQgcGxvdCBtb3RpZnN9CnRmX2xpc3RfbmFtZXMgPC0gYygpCnVwc2V0X2xpc3RfaW5wdXQgPC0gYygpCmZvciAoZGlyIGluIGMoInVwIiwgImRvd24iKSkgewogIGZvciAocGFpciBpbiBzZW5zaXRpdmVfcmVzaXN0YW50X3BhaXJzKSB7CiAgICBuYW1lIDwtIHN0cl9pbnRlcnAoIiR7cGFpcn1fJHtkaXJ9X29ubHlfdGZzIikKICAgIGxpc3QgPC0gZ2V0KHN0cl9pbnRlcnAoIiR7cGFpcn1fc2lnXyR7ZGlyfV9vbmx5X3RmcyIpKQogICAgdGZfbGlzdF9uYW1lcyA8LSBhcHBlbmQodGZfbGlzdF9uYW1lcywgbmFtZSkKICAgIHVwc2V0X2xpc3RfaW5wdXRbW2xlbmd0aCh1cHNldF9saXN0X2lucHV0KSsxXV0gPC0gbGlzdCRURiAjIG5vdGF0aW9uIG5lY2Vzc2FyeSB0byBhZGQgdG8gbGlzdCBvZiBsaXN0cwogIH0KfQoKbmFtZXModXBzZXRfbGlzdF9pbnB1dCkgPC0gdGZfbGlzdF9uYW1lcwoKdXBzZXRfZ3JvdXBzIDwtIGdldFVwc2V0UGxvdERhdGEodXBzZXRfbGlzdF9pbnB1dCkKcHJpbnQodXBzZXRfZ3JvdXBzKQp3cml0ZS50YWJsZSh1cHNldF9ncm91cHMsCiAgICAgICAgICAgICJkaWZmZXJlbnRpYWxfdGZzL3VuaWRpcmVjdGlvbmFsX2RpZmZlcmVudGlhbF90ZnNfYnlfc2Vuc2l0aXZlLXJlc2lzdGFudC1wYWlyc191cHNldF9wbG90LnR4dCIsCiAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICBjb2wubmFtZXMgPSBUUlVFLAogICAgICAgICAgICBuYSA9ICIiLAogICAgICAgICAgICBzZXAgPSAiXHQiKQoKdXBzZXQoZnJvbUxpc3QodXBzZXRfbGlzdF9pbnB1dCksIG5zZXRzID0gNywgbmludGVyc2VjdHMgPSA1MCwgb3JkZXIuYnkgPSAiZGVncmVlIiwga2VlcC5vcmRlciA9IFRSVUUsIHNldHMgPSB0Zl9saXN0X25hbWVzKQpgYGAKCjwhLS0gIyMjIENvbWJpbmUgcGVyIGlzb2xpbmUgLS0+Cgo8IS0tIGBgYHtyIGNvbWJpbmUgbWFnaWMgb3V0cHV0fSAtLT4KPCEtLSAjIFJlYWQgaW4gbWFnaWMgb3V0cHV0IGZvciBlYWNoIGlzb2xpbmUgLS0+CjwhLS0gZm9yIChpc29saW5lIGluIGMoIk9WQ0FSMyIsICJPVkNBUjQiLCAiUEVBIiwgIlBFTyIpKSB7IC0tPgo8IS0tICAgaXNvbGluZV91cF90ZnMgPC0gYXMuZGF0YS5mcmFtZSggLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9pbnRlcnAoIm1hZ2ljX291dHB1dC8ke2lzb2xpbmV9X291dHB1dC91cF9pbl9yZXNpc3RhbnQvdXBfaW5fcmVzaXN0YW50X3N1bW1hcnkueGxzeCIpKSkgLS0+CjwhLS0gICBpc29saW5lX3VwX3RmcyA8LSBpc29saW5lX3VwX3Rmc1tpc29saW5lX3VwX3RmcyRwYWRqIDwgMC41LF0gIyBJZiBwYWRqID4gMC41IHRoZW4gdGhpcyBpc24ndCByZWFsbHkgdXAgLS0+CjwhLS0gICBpc29saW5lX3VwX3Rmc19zaWcgPC0gaXNvbGluZV91cF90ZnNbaXNvbGluZV91cF90ZnMkcGFkaiA8IDAuMDUsXSAtLT4KCjwhLS0gICBpc29saW5lX2Rvd25fdGZzIDwtIGFzLmRhdGEuZnJhbWUoIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgIHJlYWRfZXhjZWwoIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2ludGVycCgibWFnaWNfb3V0cHV0LyR7aXNvbGluZX1fb3V0cHV0L2Rvd25faW5fcmVzaXN0YW50L2Rvd25faW5fcmVzaXN0YW50X3N1bW1hcnkueGxzeCIpKSkgLS0+CjwhLS0gICBpc29saW5lX2Rvd25fdGZzIDwtIGlzb2xpbmVfZG93bl90ZnNbaXNvbGluZV9kb3duX3RmcyRwYWRqIDwgMC41LF0gIyBJZiBwYWRqID4gMC41IHRoZW4gdGhpcyBpc24ndCByZWFsbHkgZG93biAtLT4KPCEtLSAgIGlzb2xpbmVfZG93bl90ZnNfc2lnIDwtIGlzb2xpbmVfZG93bl90ZnNbaXNvbGluZV9kb3duX3RmcyRwYWRqIDwgMC4wNSxdIC0tPgoKPCEtLSAgIGFzc2lnbihzdHJfaW50ZXJwKCIke2lzb2xpbmV9X3VwX3RmcyIpLCBpc29saW5lX3VwX3RmcywgcG9zID0gMSkgLS0+CjwhLS0gICBhc3NpZ24oc3RyX2ludGVycCgiJHtpc29saW5lfV9kb3duX3RmcyIpLCBpc29saW5lX2Rvd25fdGZzLCBwb3MgPSAxKSAtLT4KPCEtLSAgIGFzc2lnbihzdHJfaW50ZXJwKCIke2lzb2xpbmV9X3VwX3Rmc19zaWciKSwgaXNvbGluZV91cF90ZnNfc2lnLCBwb3MgPSAxKSAtLT4KPCEtLSAgIGFzc2lnbihzdHJfaW50ZXJwKCIke2lzb2xpbmV9X2Rvd25fdGZzX3NpZyIpLCBpc29saW5lX2Rvd25fdGZzX3NpZywgcG9zID0gMSkgLS0+CjwhLS0gfSAtLT4KCjwhLS0gIyBBbGwgdGZzIHRoYXQgYXJlIHNpZ25pZmljYW50IGluIGF0IGxlYXN0IG9uZSBpc29saW5lIC0tPgo8IS0tIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93biA8LSBkYXRhLmZyYW1lKFRGID0gdW5pcXVlKGxpc3QuYXBwZW5kKE9WQ0FSM19kb3duX3Rmc19zaWckVEYsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9WQ0FSNF9kb3duX3Rmc19zaWckVEYsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBFT19kb3duX3Rmc19zaWckVEYsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBFQV9kb3duX3Rmc19zaWckVEYpKSkgLS0+CjwhLS0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cCA8LSBkYXRhLmZyYW1lKFRGID0gdW5pcXVlKGxpc3QuYXBwZW5kKE9WQ0FSM191cF90ZnNfc2lnJFRGLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT1ZDQVI0X3VwX3Rmc19zaWckVEYsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQRU9fdXBfdGZzX3NpZyRURiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBFQV91cF90ZnNfc2lnJFRGKSkpIC0tPgoKPCEtLSBmb3IgKGlzb2xpbmUgaW4gYygiT1ZDQVIzIiwgIk9WQ0FSNCIsICJQRUEiLCAiUEVPIikpIHsgLS0+CjwhLS0gICBpc29saW5lX3VwX3RmcyA8LSBnZXQoc3RyX2ludGVycCgiJHtpc29saW5lfV91cF90ZnMiKSkgLS0+CjwhLS0gICBpc29saW5lX2FkZGl0aW9uX3VwIDwtIGRhdGEuZnJhbWUoaXNvbGluZV91cF90ZnMkVEYsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzb2xpbmVfdXBfdGZzJFNjb3JlLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc29saW5lX3VwX3RmcyRwYWRqKSAtLT4KCjwhLS0gICBjb2xuYW1lcyhpc29saW5lX2FkZGl0aW9uX3VwKSA8LSBjKCJURiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9pbnRlcnAoIiR7aXNvbGluZX1fdXBfc2NvcmUiKSwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2ludGVycCgiJHtpc29saW5lfV91cF9wYWRqIikpIC0tPgoKPCEtLSAgIGlzb2xpbmVfZG93bl90ZnMgPC0gZ2V0KHN0cl9pbnRlcnAoIiR7aXNvbGluZX1fZG93bl90ZnMiKSkgLS0+Cgo8IS0tICAgaXNvbGluZV9hZGRpdGlvbl9kb3duIDwtIGRhdGEuZnJhbWUoaXNvbGluZV9kb3duX3RmcyRURiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc29saW5lX2Rvd25fdGZzJFNjb3JlLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzb2xpbmVfZG93bl90ZnMkcGFkaikgLS0+Cgo8IS0tICAgY29sbmFtZXMoaXNvbGluZV9hZGRpdGlvbl9kb3duKSA8LSBjKCJURiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2ludGVycCgiJHtpc29saW5lfV9kb3duX3Njb3JlIiksIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2ludGVycCgiJHtpc29saW5lfV9kb3duX3BhZGoiKSkgLS0+Cgo8IS0tICAgIyBBZGQgdGhlIGluZm8gZm9yIHVwIGFuZCBkb3duIGFjcm9zcyBhbGwgaXNvbGluZXMgcmVnYXJkbGVzcyBvZiBzaWduaWZpY2FuY2UgLS0+CjwhLS0gICBpZiAobnJvdyhpc29saW5lX2FkZGl0aW9uX3VwKSA+IDApIHsgLS0+CjwhLS0gICAgIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXAgPC0gbGVmdF9qb2luKGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXAsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc29saW5lX2FkZGl0aW9uX3VwLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiVEYiKSAtLT4KPCEtLSAgICAgY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duIDwtIGxlZnRfam9pbihjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd24sIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzb2xpbmVfYWRkaXRpb25fdXAsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIlRGIikgLS0+CjwhLS0gICB9IC0tPgoKPCEtLSAgIGlmIChucm93KGlzb2xpbmVfYWRkaXRpb25fZG93bikgPiAwKSB7IC0tPgo8IS0tICAgICBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwIDwtIGxlZnRfam9pbihjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNvbGluZV9hZGRpdGlvbl9kb3duLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiVEYiKSAtLT4KPCEtLSAgICAgY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duIDwtIGxlZnRfam9pbihjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd24sIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzb2xpbmVfYWRkaXRpb25fZG93biwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiVEYiKSAtLT4KPCEtLSAgIH0gLS0+CjwhLS0gfSAtLT4KCjwhLS0gIyBDb3VudCB0aGUgbnVtYmVyIG9mIGlzb2xpbmVzIHRoYXQgd2VyZSBzaWduaWZpY2FudGx5IHVwL2Rvd24gaW4gZWFjaCBURiAtLT4KPCEtLSBmb3IgKHJvdyBpbiAxOm5yb3coY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cCkpIHsgLS0+CjwhLS0gICBudW1fc2lnX3VwIDwtIDAgLS0+CjwhLS0gICBmb3IgKGNvbCBpbiBjKCJPVkNBUjNfdXBfcGFkaiIsICJPVkNBUjRfdXBfcGFkaiIsICJQRU9fdXBfcGFkaiIsICJQRUFfdXBfcGFkaiIpKSB7IC0tPgo8IS0tICAgICBwYWRqIDwtIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXBbcm93LCBjb2xdIC0tPgo8IS0tICAgICBpZiAoIWlzLm5hKHBhZGopICYgcGFkaiA8IDAuMDUpIHsgLS0+CjwhLS0gICAgICAgbnVtX3NpZ191cCA8LSBudW1fc2lnX3VwICsgMSAtLT4KPCEtLSAgICAgfSAtLT4KPCEtLSAgIH0gLS0+Cgo8IS0tICAgbnVtX3NpZ19kb3duIDwtIDAgLS0+CjwhLS0gICBmb3IgKGNvbCBpbiBjKCJPVkNBUjNfZG93bl9wYWRqIiwgIk9WQ0FSNF9kb3duX3BhZGoiLCAiUEVPX2Rvd25fcGFkaiIsICJQRUFfZG93bl9wYWRqIikpIHsgLS0+CjwhLS0gICAgIHBhZGogPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cFtyb3csIGNvbF0gLS0+CjwhLS0gICAgIGlmICghaXMubmEocGFkaikgJiBwYWRqIDwgMC4wNSkgeyAtLT4KPCEtLSAgICAgICBudW1fc2lnX2Rvd24gPC0gbnVtX3NpZ19kb3duICsgMSAtLT4KPCEtLSAgICAgfSAtLT4KPCEtLSAgIH0gLS0+Cgo8IS0tICAgY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cFtyb3csICJudW1faXNvbGluZXNfc2lnX3VwIl0gPC0gbnVtX3NpZ191cCAtLT4KPCEtLSAgIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXBbcm93LCAibnVtX2lzb2xpbmVzX3NpZ19kb3duIl0gPC0gbnVtX3NpZ19kb3duIC0tPgo8IS0tIH0gLS0+Cgo8IS0tICMgQ291bnQgdGhlIG51bWJlciBvZiBpc29saW5lcyB0aGF0IHdlcmUgc2lnbmlmaWNhbnRseSB1cC9kb3duIGluIGVhY2ggVEYgLS0+CjwhLS0gZm9yIChyb3cgaW4gMTpucm93KGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bikpIHsgLS0+CjwhLS0gICBudW1fc2lnX3VwIDwtIDAgLS0+CjwhLS0gICBmb3IgKGNvbCBpbiBjKCJPVkNBUjNfdXBfcGFkaiIsICJPVkNBUjRfdXBfcGFkaiIsICJQRU9fdXBfcGFkaiIsICJQRUFfdXBfcGFkaiIpKSB7IC0tPgo8IS0tICAgICBwYWRqIDwtIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bltyb3csIGNvbF0gLS0+CjwhLS0gICAgIGlmICghaXMubmEocGFkaikgJiBwYWRqIDwgMC4wNSkgeyAtLT4KPCEtLSAgICAgICBudW1fc2lnX3VwIDwtIG51bV9zaWdfdXAgKyAxIC0tPgo8IS0tICAgICB9IC0tPgo8IS0tICAgfSAtLT4KCjwhLS0gICBudW1fc2lnX2Rvd24gPC0gMCAtLT4KPCEtLSAgIGZvciAoY29sIGluIGMoIk9WQ0FSM19kb3duX3BhZGoiLCAiT1ZDQVI0X2Rvd25fcGFkaiIsICJQRU9fZG93bl9wYWRqIiwgIlBFQV9kb3duX3BhZGoiKSkgeyAtLT4KPCEtLSAgICAgcGFkaiA8LSBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd25bcm93LCBjb2xdIC0tPgo8IS0tICAgICBpZiAoIWlzLm5hKHBhZGopICYgcGFkaiA8IDAuMDUpIHsgLS0+CjwhLS0gICAgICAgbnVtX3NpZ19kb3duIDwtIG51bV9zaWdfZG93biArIDEgLS0+CjwhLS0gICAgIH0gLS0+CjwhLS0gICB9IC0tPgoKPCEtLSAgIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bltyb3csICJudW1faXNvbGluZXNfc2lnX3VwIl0gPC0gbnVtX3NpZ191cCAtLT4KPCEtLSAgIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bltyb3csICJudW1faXNvbGluZXNfc2lnX2Rvd24iXSA8LSBudW1fc2lnX2Rvd24gLS0+CjwhLS0gfSAtLT4KCjwhLS0gIyBSZW9yZGVyIGNvbHVtbnMgLS0+CjwhLS0gcm93bmFtZXMoY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cCkgPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cCRURiAtLT4KPCEtLSBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwIDwtIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXBbLCBjKCJURiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm51bV9pc29saW5lc19zaWdfdXAiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJudW1faXNvbGluZXNfc2lnX2Rvd24iLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPVkNBUjNfdXBfc2NvcmUiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPVkNBUjNfdXBfcGFkaiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSNF91cF9zY29yZSIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSNF91cF9wYWRqIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVPX3VwX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVPX3VwX3BhZGoiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQRUFfdXBfc2NvcmUiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQRUFfdXBfcGFkaiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSM19kb3duX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT1ZDQVIzX2Rvd25fcGFkaiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSNF9kb3duX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT1ZDQVI0X2Rvd25fcGFkaiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBFT19kb3duX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVPX2Rvd25fcGFkaiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBFQV9kb3duX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVBX2Rvd25fcGFkaiIpXSAtLT4KCjwhLS0gcm93bmFtZXMoY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duKSA8LSBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd24kVEYgLS0+CjwhLS0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duIDwtIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93blssIGMoIlRGIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm51bV9pc29saW5lc19zaWdfZG93biIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJudW1faXNvbGluZXNfc2lnX3VwIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSM19kb3duX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSM19kb3duX3BhZGoiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT1ZDQVI0X2Rvd25fc2NvcmUiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT1ZDQVI0X2Rvd25fcGFkaiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQRU9fZG93bl9zY29yZSIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQRU9fZG93bl9wYWRqIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBFQV9kb3duX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBFQV9kb3duX3BhZGoiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT1ZDQVIzX3VwX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSM191cF9wYWRqIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9WQ0FSNF91cF9zY29yZSIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPVkNBUjRfdXBfcGFkaiIsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQRU9fdXBfc2NvcmUiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVPX3VwX3BhZGoiLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVBX3VwX3Njb3JlIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBFQV91cF9wYWRqIildIC0tPgoKPCEtLSAjIFNvcnQgYnkgbnVtIHNpZ25pZmljYW50IC0tPgo8IS0tIGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXAgPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ191cFtvcmRlcihjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX3VwJG51bV9pc29saW5lc19zaWdfdXAsIGRlY3JlYXNpbmc9VFJVRSksXSAtLT4KPCEtLSBjb21iaW5lZF9tYWdpY19vdXRwdXRfc2lnX2Rvd24gPC0gY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duW29yZGVyKGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93biRudW1faXNvbGluZXNfc2lnX2Rvd24sIGRlY3JlYXNpbmc9VFJVRSksXSAtLT4KCjwhLS0gIyBUYWJsZXMgaW5jbHVkZSBURiBpbmZvIGFjcm9zcyBhbGwgaXNvbGluZXMgZm9yIGVhY2ggdGYgdGhhdCBpcyB1cC9kb3duIHJlZ3VsYXRlZCBzaWduaWZpY2FudGx5IGluIGF0IGxlYXN0IG9uZSBpc29saW5lIC0tPgo8IS0tIHByaW50KGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXApIC0tPgo8IS0tIHByaW50KGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfZG93bikgLS0+Cgo8IS0tIHdyaXRlLnRhYmxlKGNvbWJpbmVkX21hZ2ljX291dHB1dF9zaWdfdXAsIC0tPgo8IS0tICAgICAgICAgICAgIGZpbGUgPSBzdHJfaW50ZXJwKCJkaWZmZXJlbnRpYWxfdGZzL2NvbWJpbmVkX21hZ2ljX291dHB1dF91cF9zaWdfaXNvbGluZXMudHh0IiksIC0tPgo8IS0tICAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsIC0tPgo8IS0tICAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLCAtLT4KPCEtLSAgICAgICAgICAgICBuYSA9ICIiLCAtLT4KPCEtLSAgICAgICAgICAgICBzZXAgPSAiXHQiKSAtLT4KCjwhLS0gd3JpdGUudGFibGUoY29tYmluZWRfbWFnaWNfb3V0cHV0X3NpZ19kb3duLCAtLT4KPCEtLSAgICAgICAgICAgICBmaWxlID0gc3RyX2ludGVycCgiZGlmZmVyZW50aWFsX3Rmcy9jb21iaW5lZF9tYWdpY19vdXRwdXRfZG93bl9zaWdfaXNvbGluZXMudHh0IiksIC0tPgo8IS0tICAgICAgICAgICAgIHF1b3RlID0gRkFMU0UsIC0tPgo8IS0tICAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLCAtLT4KPCEtLSAgICAgICAgICAgICBuYSA9ICIiLCAtLT4KPCEtLSAgICAgICAgICAgICBzZXAgPSAiXHQiKSAtLT4KPCEtLSBgYGAgLS0+Cg==